aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-04-28 00:07:37 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-04-28 00:07:37 -0700
commit12073e3c27b0b571dd340fd7a587c90427042ff3 (patch)
treeb9279537eeb8549ed2a6697fd1967c918380105b
parentfa7b9cdb6b136254c2b56ceaaf0452d92e159e48 (diff)
downloadpw-12073e3c27b0b571dd340fd7a587c90427042ff3.tar.gz
pw-12073e3c27b0b571dd340fd7a587c90427042ff3.tar.bz2
pw-12073e3c27b0b571dd340fd7a587c90427042ff3.zip
New feature: grep mode with pattern stack.
-rw-r--r--pw.134
-rw-r--r--pw.c121
2 files changed, 131 insertions, 24 deletions
diff --git a/pw.1 b/pw.1
index 6effc43..755d220 100644
--- a/pw.1
+++ b/pw.1
@@ -230,6 +230,40 @@ Append the current contents of the display into the specified file.
.IP "\fB:!\fP \fIfilename\fP"
Pipe the current contents of of the display into the specified command.
+
+.IP "\fB:g\fP \fIpattern\fP, \fB:v\fP \fIpattern\fP"
+Push a
+.I grep
+pattern onto the grep stack. The
+.B :g
+command pushes a plain pattern; the
+.B :v
+command pushes a logically inverted pattern. The grep stack holds up to 64
+patterns. If the pattern is successfully pushed onto the stack, it
+restricts which lines are admitted into the FIFO and available for display.
+The plain pattern admits only the lines which match
+.IR pattern ;
+the inverted pattern admits only lines which do
+.I not
+match
+.IR pattern .
+The status line shows
+.B GREP
+.BI ( depth )
+to indicate that grep mode and the depth of the stack. Lines which are
+already in the FIFO are not affected.
+
+.IP \fB:r\fP[\fB!\fP]
+Remove and forget the most recent grep pattern
+.RB ( :g or :v )
+from the grep stack. If the stack depth decrements from 1, the grep mode
+is disabled and the
+.B GREP
+status line disappears. If the optional
+.B !
+modifier is included in the command, then it pops the entire stack,
+forgetting all the patterns and disabling grep mode.
+
.PP
Any other command results in a brief error message.
diff --git a/pw.c b/pw.c
index fdd5846..34e5feb 100644
--- a/pw.c
+++ b/pw.c
@@ -21,9 +21,19 @@ enum status_flags {
stat_susp = 4, // display refresh suspended
stat_htmode = 8, // head trigger mode
stat_ttmode = 16, // tail trigger mode
- stat_trgrd = 32 // triggered flag
+ stat_trgrd = 32, // triggered flag
+ stat_grep = 64 // grep mode
};
+typedef struct grep {
+ char *pat;
+ regex_t rx;
+ int inv;
+} grep;
+
+#define cmdsize 100
+#define maxgrep 64
+
typedef struct dstr {
int refs;
size_t len;
@@ -37,6 +47,9 @@ int snaplines;
char *trigpat;
regex_t trigex;
+grep grepstack[maxgrep];
+int ngrep;
+
static void panic(const char *fmt, ...)
{
va_list vl;
@@ -201,10 +214,14 @@ static void drawstatus(unsigned stat, char *cmd)
{
if (cmd) {
printf("%s", cmd);
- } else if ((stat & (stat_eof | stat_susp | stat_htmode | stat_ttmode))) {
+ } else if ((stat & (stat_eof | stat_susp | stat_htmode | stat_ttmode |
+ stat_grep)))
+ {
if ((stat & stat_eof))
printf("EOF ");
- else if ((stat & stat_htmode))
+ if ((stat & stat_grep))
+ printf("GREP (%d) ", ngrep);
+ if ((stat & stat_htmode))
printf("TRIG (/%s) ", trigpat);
else if ((stat & stat_ttmode))
printf("TRIG (?%s) ", trigpat);
@@ -241,7 +258,7 @@ static void redraw(char **circbuf, int nlines, int hpos,
drawstatus(stat, cmd);
}
-static void execute(char *cmd)
+static void execute(char *cmd, unsigned *pstat)
{
char *arg = cmd + 2 + strspn(cmd + 2, " \t");
@@ -300,6 +317,47 @@ static void execute(char *cmd)
sprintf(cmd, "piped!");
}
break;
+ case 'g':
+ case 'v':
+ {
+ int err;
+ grep *gr = &grepstack[ngrep];
+
+ if (arg[0] == 0) {
+ sprintf(cmd, "pattern required!");
+ break;
+ }
+
+ if (ngrep >= maxgrep) {
+ sprintf(cmd, "too many greps");
+ break;
+ }
+
+ if ((err = regcomp(&gr->rx, arg, REG_EXTENDED | REG_NOSUB)) != 0) {
+ regerror(err, &gr->rx, cmd, cmdsize);
+ break;
+ }
+
+ gr->pat = dsdup(arg);
+
+ if (cmd[1] == 'v')
+ gr->inv = 1;
+
+ if (ngrep++ == 0)
+ *pstat |= stat_grep;
+ }
+ break;
+ case 'r':
+ while (ngrep > 0) {
+ grep *gr = &grepstack[--ngrep];
+ regfree(&gr->rx);
+ dsdrop(gr->pat);
+ if (cmd[2] != '!')
+ break;
+ }
+ if (ngrep == 0)
+ *pstat &= ~stat_grep;
+ break;
default:
sprintf(cmd, "bad command");
break;
@@ -328,7 +386,7 @@ int main(int argc, char **argv)
};
int auto_quit = 1;
int exit_status = EXIT_FAILURE;
- char cmdbuf[100], *curcmd = 0;
+ char cmdbuf[cmdsize], *curcmd = 0;
if (fd < 0)
panic("unable to obtain input file descriptor");
@@ -435,27 +493,42 @@ int main(int argc, char **argv)
} else {
nfds = 1;
line = addch(line, 0);
- if ((stat & stat_htmode))
- if (regexec(&trigex, line, 0, NULL, 0) == 0)
- stat |= stat_trgrd;
- if (nlines == maxlines) {
- dsdrop(circbuf[0]);
- memmove(circbuf, circbuf + 1, (nlines - 1) * sizeof *circbuf);
- circbuf[nlines - 1] = line;
- stat |= stat_dirty;
- if ((stat & stat_ttmode))
- if (regexec(&trigex, circbuf[0], 0, NULL, 0) == 0)
+ if ((stat & stat_grep)) {
+ int i;
+ for (i = 0; i < ngrep; i++) {
+ grep *gr = &grepstack[i];
+ int match = regexec(&gr->rx, line, 0, NULL, 0) == 0;
+ if (match == gr->inv)
+ break;
+ }
+ if (i < ngrep) {
+ dsdrop(line);
+ line = 0;
+ }
+ }
+ if (line) {
+ if ((stat & stat_htmode))
+ if (regexec(&trigex, line, 0, NULL, 0) == 0)
stat |= stat_trgrd;
- } else {
- circbuf[nlines++] = line;
- if ((stat & stat_susp) == 0) {
- snapshot[snaplines++] = dsref(line);
- clrline();
- drawline(line, hpos, columns);
- drawstatus(stat, curcmd);
+ if (nlines == maxlines) {
+ dsdrop(circbuf[0]);
+ memmove(circbuf, circbuf + 1, (nlines - 1) * sizeof *circbuf);
+ circbuf[nlines - 1] = line;
+ stat |= stat_dirty;
+ if ((stat & stat_ttmode))
+ if (regexec(&trigex, circbuf[0], 0, NULL, 0) == 0)
+ stat |= stat_trgrd;
+ } else {
+ circbuf[nlines++] = line;
+ if ((stat & stat_susp) == 0) {
+ snapshot[snaplines++] = dsref(line);
+ clrline();
+ drawline(line, hpos, columns);
+ drawstatus(stat, curcmd);
+ }
}
+ line = 0;
}
- line = 0;
}
} else {
nfds = 1;
@@ -606,7 +679,7 @@ int main(int argc, char **argv)
stat |= stat_dirty;
if (ch == 13) {
if (kbd_state == kbd_colon && cmdbuf[1]) {
- execute(cmdbuf);
+ execute(cmdbuf, &stat);
if (cmdbuf[0] != 0) {
kbd_state = kbd_result;
break;