From 18bb2575caffe7f4d16ed967e52072a8518d8ba0 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Mon, 15 Jan 2024 16:25:01 -0500 Subject: Smart case by default --- bp.1 | 29 ++++++++++++++++++++++++++++- bp.1.md | 3 +++ bp.c | 23 +++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/bp.1 b/bp.1 index 1e7f46e..5f1a01c 100644 --- a/bp.1 +++ b/bp.1 @@ -1,12 +1,30 @@ -.\" Automatically generated by Pandoc 3.1.8 +.\" Automatically generated by Pandoc 3.1.6 .\" +.\" Define V font for inline verbatim, using C font in formats +.\" that render this, and otherwise B font. +.ie "\f[CB]x\f[]"x" \{\ +. ftr V B +. ftr VI BI +. ftr VB B +. ftr VBI BI +.\} +.el \{\ +. ftr V CR +. ftr VI CI +. ftr VB CB +. ftr VBI CBI +.\} .TH "BP" "1" "May 17 2021" "" "" +.hy .SH NAME +.PP bp - Bruce\[aq]s Parsing Expression Grammar tool .SH SYNOPSIS +.PP \f[B]bp\f[R] [\f[I]options\&...\f[R]] \f[I]pattern\f[R] [[\f[B]--\f[R]] \f[I]files\&...\f[R]] .SH DESCRIPTION +.PP \f[B]bp\f[R] is a tool that matches parsing expression grammars using a custom syntax. .SH OPTIONS @@ -32,6 +50,11 @@ Print a JSON list of the matches. Print only the names of files containing matches instead of the matches themselves. .TP +\f[B]-c\f[R], \f[B]--case\f[R] +Perform pattern matching with case-sensitivity (the default is smart +casing, i.e.\ case-insensitive, unless there are any uppercase letters +present). +.TP \f[B]-i\f[R], \f[B]--ignore-case\f[R] Perform pattern matching case-insensitively. .TP @@ -92,6 +115,7 @@ used instead. If neither are provided, \f[B]bp\f[R] will search through all files in the current directory and its subdirectories (recursively). .SH STRING PATTERNS +.PP One of the most common use cases for pattern matching tools is matching plain, literal strings, or strings that are primarily plain strings, with one or two patterns. @@ -108,6 +132,7 @@ character literal: \f[B]{\[ga]{}\f[R], the string literal: \f[B]{\[dq]{\[dq]}\f[R], or a pair of matching curly braces using the \f[B]braces\f[R] rule: \f[B]{braces}\f[R]. .SH PATTERNS +.PP \f[B]bp\f[R] patterns are based off of a combination of Parsing Expression Grammars and regular expression syntax. The syntax is designed to map closely to verbal descriptions of the @@ -352,6 +377,7 @@ that also attaches a metadata tag of the same name) \f[B]#\f[R] \f[I]comment\f[R] A line comment, ignored by BP .SH GRAMMAR FILES +.PP \f[B]bp\f[R] allows loading extra grammar files, which define patterns which may be used for matching. The \f[B]builtins\f[R] grammar file is loaded by default, and it defines @@ -404,6 +430,7 @@ following command: \f[B]bp -g c++ \[aq]{comment \[ti] \[dq]TODO\[dq]}\[aq] *.cpp\f[R] .RE .SH EXAMPLES +.PP Find files containing the literal string \[lq]foo.baz\[rq] (a string pattern): .RS diff --git a/bp.1.md b/bp.1.md index 97f12f4..7679936 100644 --- a/bp.1.md +++ b/bp.1.md @@ -34,6 +34,9 @@ syntax. : Print only the names of files containing matches instead of the matches themselves. +`-c`, `--case` +: Perform pattern matching with case-sensitivity (the default is smart casing, i.e. case-insensitive, unless there are any uppercase letters present). + `-i`, `--ignore-case` : Perform pattern matching case-insensitively. diff --git a/bp.c b/bp.c index dce1d4a..68c07d0 100644 --- a/bp.c +++ b/bp.c @@ -40,6 +40,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" + " -c --case use case sensitivity\n" " -i --ignore-case preform matching case-insensitively\n" " -I --inplace modify a file in-place\n" " -l --list-files list filenames only\n" @@ -538,6 +539,18 @@ static int context_from_flag(const char *flag) return (int)strtol(flag, NULL, 10); } +// +// Check if any letters are uppercase +// +static bool any_uppercase(const char *str) +{ + for (; *str; ++str) { + if (isupper(*str)) + return true; + } + return false; +} + #define FLAG(f) (flag = get_flag(argv, f, &argv)) #define BOOLFLAG(f) get_boolflag(argv, f, &argv) @@ -555,6 +568,8 @@ int main(int argc, char *argv[]) file_t *local_file = load_filef(&loaded_files, "%s/.config/"BP_NAME"/builtins.bp", getenv("HOME")); if (local_file) defs = load_grammar(defs, local_file); + bool explicit_case_sensitivity = false; + ++argv; // skip program name while (argv[0]) { if (streq(argv[0], "--")) { @@ -577,6 +592,10 @@ int main(int argc, char *argv[]) options.git_mode = true; } else if (BOOLFLAG("-i") || BOOLFLAG("--ignore-case")) { options.ignorecase = true; + explicit_case_sensitivity = true; + } else if (BOOLFLAG("-c") || BOOLFLAG("--case")) { + options.ignorecase = false; + explicit_case_sensitivity = true; } else if (BOOLFLAG("-l") || BOOLFLAG("--list-files")) { options.mode = MODE_LISTFILES; } else if (FLAG("-r") || FLAG("--replace")) { @@ -601,6 +620,8 @@ int main(int argc, char *argv[]) } else if (FLAG("-w") || FLAG("--word")) { require(asprintf(&flag, "{|}%s{|}", flag), "Could not allocate memory"); file_t *arg_file = spoof_file(&loaded_files, "", flag, -1); + if (!explicit_case_sensitivity) + options.ignorecase = !any_uppercase(flag); delete(&flag); pat_t *p = assert_pat(arg_file->start, arg_file->end, bp_stringpattern(arg_file->start, arg_file->end)); pattern = chain_together(pattern, p); @@ -627,6 +648,8 @@ int main(int argc, char *argv[]) } else if (argv[0][0] != '-') { if (pattern != NULL) break; pat_t *p = assert_pat(argv[0], NULL, bp_stringpattern(argv[0], argv[0]+strlen(argv[0]))); + if (!explicit_case_sensitivity) + options.ignorecase = !any_uppercase(argv[0]); pattern = chain_together(pattern, p); ++argv; } else { -- cgit v1.2.3