aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/globals.h23
-rw-r--r--src/main.c23
-rw-r--r--src/work.c30
3 files changed, 67 insertions, 9 deletions
diff --git a/src/globals.h b/src/globals.h
index 1285db3..f0ed91b 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -15,15 +15,22 @@ typedef struct {
#endif
} op_t;
+enum {
+ HDR_NEVER,
+ HDR_MULTI,
+ HDR_ALWAYS,
+};
+
typedef struct {
- bool b : 1;
- bool c : 1;
- bool i : 1;
- bool l : 1;
- bool p : 1;
- bool s : 1;
- bool U : 1;
- bool z : 1;
+ bool b : 1;
+ bool c : 1;
+ unsigned H : 2;
+ bool i : 1;
+ bool l : 1;
+ bool p : 1;
+ bool s : 1;
+ bool U : 1;
+ bool z : 1;
#if !GIT_GRAB
bool do_header : 1;
diff --git a/src/main.c b/src/main.c
index a71b554..a386362 100644
--- a/src/main.c
+++ b/src/main.c
@@ -69,6 +69,7 @@ main(int argc, char **argv)
{'b', U8C("byte-offset"), CLI_NONE},
{'c', U8C("color"), CLI_NONE},
{'h', U8C("help"), CLI_NONE},
+ {'H', U8C("header-line"), CLI_REQ},
{'i', U8C("ignore-case"), CLI_NONE},
{'l', U8C("literal"), CLI_NONE},
{'L', U8C("line-position"), CLI_NONE},
@@ -95,6 +96,26 @@ main(int argc, char **argv)
case 'h':
execlp("man", "man", "1", mlib_progname(), nullptr);
err("execlp: man 1 %s:", mlib_progname());
+ case 'H':
+ if (ucseq(parser.optarg, U8("never")))
+ flags.H = HDR_NEVER;
+ else if (ucseq(parser.optarg, U8("multi")))
+ flags.H = HDR_MULTI;
+ else if (ucseq(parser.optarg, U8("always")))
+ flags.H = HDR_ALWAYS;
+ else if (parser.optarg.len == 0) {
+ warn("empty value given for option %s--header-line%s",
+ lquot, rquot);
+ goto usage;
+ } else {
+ warn("unknown value %s%.*s%s for option %s--header-line%s",
+ lquot, SV_PRI_ARGS(parser.optarg), rquot, lquot, rquot);
+ goto usage;
+ }
+#if !GIT_GRAB
+ flags.do_header = true;
+#endif
+ break;
case 'i':
flags.i = true;
break;
@@ -130,7 +151,7 @@ main(int argc, char **argv)
if (argc == 0) {
usage:
- usage("[-bcilLpsUz] pattern [file ...]", "-h");
+ usage("[-H never|multi|always] [-bcilLpsUz] pattern [file ...]", "-h");
exit(EXIT_FATAL);
}
diff --git a/src/work.c b/src/work.c
index bf66fdb..c8a3e21 100644
--- a/src/work.c
+++ b/src/work.c
@@ -18,6 +18,7 @@
#include <macros.h>
#include <mbstring.h>
#include <pcre2.h>
+#include <rune.h>
#include <unicode/string.h>
#include "exitcodes.h"
@@ -39,6 +40,7 @@ typedef struct {
} pos_state_t;
static void compute_pos(const char8_t *p, pos_state_t *ps);
+static bool has_lbrk_p(u8view_t sv);
static bool islbrk(u8view_t g);
static int svposcmp(const void *a, const void *b);
static void write_match_to_buffer(u8view_t sv, u8view_t *hl);
@@ -375,6 +377,15 @@ write_match_to_buffer(u8view_t sv, u8view_t *hl)
array_extend_sv(buf, COL_SE);
array_push(buf, sep);
array_extend_sv(buf, COL_RS);
+
+ switch (flags.H) {
+ case HDR_ALWAYS:
+ array_push(buf, '\n');
+ break;
+ case HDR_MULTI:
+ if (has_lbrk_p(sv))
+ array_push(buf, '\n');
+ }
}
#pragma GCC diagnostic pop
@@ -453,6 +464,25 @@ compute_pos(const char8_t *p, pos_state_t *ps)
}
bool
+has_lbrk_p(u8view_t sv)
+{
+ rune ch;
+ while (ucsnext(&ch, &sv) != 0) {
+ switch (ch) {
+ case '\r': /* Not *really* a newline, but it can mess with output */
+ case '\n':
+ case '\v':
+ case '\f':
+ case 0x85:
+ case RUNE_C(0x2028):
+ case RUNE_C(0x2029):
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
islbrk(u8view_t g)
{
return ucseq(g, U8("\n"))