From 58af933f4e70e2b85b11ca05c799fce226ed1821 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 17 Jan 2021 09:21:58 -0800 Subject: [PATCH] Added --git/-G --- README.md | 5 +++-- bp.1 | 5 +++++ bp.c | 39 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ec01682..1050f72 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,10 @@ It's written in pure C with no dependencies. * `-l` `--list-files` print only filenames containing matches * `-p` `--pattern ` provide a pattern (equivalent to `bp '\()'`) * `-P` `--pattern-string ` provide a string pattern (equivalent to `bp ''`, but may be useful if `''` begins with a '-') -* `-r` `--replace ` replace the input pattern with the given replacement +* `-r` `--replace ` replace the input pattern with the given replacement * `-c` `--context ` change how many lines of context are printed (`0`: no context, `all`: the whole file, `` matching lines and `` lines before/after) -* `-g` `--grammar ` use the specified file as a grammar +* `-g` `--grammar ` use the specified file as a grammar +* `-G` `--git` get filenames from git See `man ./bp.1` for more details. diff --git a/bp.1 b/bp.1 index 14303bb..ef56199 100644 --- a/bp.1 +++ b/bp.1 @@ -17,6 +17,7 @@ bp \- Bruce's Parsing Expression Grammar tool [\fI-P\fR|\fI--pattern-string\fR \fI\fR] [\fI-r\fR|\fI--replace\fR \fI\fR] [\fI-g\fR|\fI--grammar\fR \fI\fR] +[\fI-G\fR|\fI--git\fR] [\fI-c\fR|\fI--conntext\fR \fI\fR] \fI\fR] @@ -50,6 +51,10 @@ Replace all occurrences of the main pattern with the given string. .B \-g\fR, \fB--grammar \fI\fR Load the grammar from the given file. +.B \-G\fR, \fB--git\fR +Use \fBgit\fR to get a list of files. Remaining file arguments (if any) are +passed to \fBgit --ls-files\fR instead of treated as literal files. + .B \-c\fR, \fB--context \fI\fR The number of lines of context to print. If \fI\fR is 0, print only the exact text of the matches. If \fI\fR is "all", print the entire file. diff --git a/bp.c b/bp.c index 15cc4bb..ea66e02 100644 --- a/bp.c +++ b/bp.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include "definitions.h" @@ -379,8 +381,8 @@ int main(int argc, char *argv[]) file_t *local_file = load_file(&loaded_files, "%s/.config/"BP_NAME"/builtins.bp", getenv("HOME")); if (local_file) defs = load_grammar(defs, local_file); - int i, npatterns = 0; check(argc > 1, "%s", usage); + int i, npatterns = 0, git = 0; for (i = 1; i < argc; i++) { if (streq(argv[i], "--")) { ++i; @@ -399,6 +401,8 @@ int main(int argc, char *argv[]) mode = MODE_INPLACE; } else if (streq(argv[i], "--confirm")) { confirm = CONFIRM_ASK; + } else if (streq(argv[i], "--git")) { + git = 1; } else if (streq(argv[i], "--ignore-case")) { ignorecase = 1; } else if (streq(argv[i], "--list-files")) { @@ -460,6 +464,7 @@ int main(int argc, char *argv[]) switch (*c) { case 'h': goto flag_help; // -h case 'v': verbose = 1; break; // -v + case 'G': git = 1; break; // -G case 'e': mode = MODE_EXPLAIN; break; // -e case 'j': mode = MODE_JSON; break; // -j case 'I': mode = MODE_INPLACE; break; // -I @@ -512,7 +517,37 @@ int main(int argc, char *argv[]) int found = 0; if (mode == MODE_JSON) printf("["); - if (i < argc) { + if (git) { + int fds[2]; + check(pipe(fds) == 0, "Failed to create pipe"); + pid_t child = fork(); + check(child != -1, "Failed to fork"); + if (child == 0) { + char **git_args = calloc((size_t)(2+(argc-i)+1), sizeof(char*)); + int g = 0; + git_args[g++] = "git"; + git_args[g++] = "ls-files"; + while (i < argc) git_args[g++] = argv[i++]; + dup2(fds[STDOUT_FILENO], STDOUT_FILENO); + close(fds[STDIN_FILENO]); + execvp("git", git_args); + _exit(1); + } + close(fds[STDOUT_FILENO]); + char path[PATH_MAX+2] = {0}; // path + \n + \0 + while (read(fds[STDIN_FILENO], path, PATH_MAX+1) > 0) { // Iterate over chunks + for (char *nl; (nl = strchr(path, '\n')); ) { // Iterate over nl-terminated lines + *nl = '\0'; + found += process_file(defs, path, pattern); + memmove(path, nl+1, sizeof(path)-(size_t)(nl+1-path)); + } + } + close(fds[STDIN_FILENO]); + int status; + waitpid(child, &status, 0); + check(WIFEXITED(status) && WEXITSTATUS(status) == 0, + "`git --ls-files` failed. Do you have git installed?"); + } else 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);