Moving print logic out of match.c and renaming explain -> printmatch
This commit is contained in:
parent
c51a91c470
commit
326a0b960c
2
Makefile
2
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
|
||||
|
@ -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.
|
||||
|
||||
|
2
bp.c
2
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
|
||||
|
13
explain.h
13
explain.h
@ -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
|
87
match.c
87
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
|
||||
|
9
match.h
9
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
|
||||
|
@ -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
|
22
printmatch.h
Normal file
22
printmatch.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user