diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2022-04-28 00:07:37 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2022-04-28 00:07:37 -0700 |
commit | 12073e3c27b0b571dd340fd7a587c90427042ff3 (patch) | |
tree | b9279537eeb8549ed2a6697fd1967c918380105b | |
parent | fa7b9cdb6b136254c2b56ceaaf0452d92e159e48 (diff) | |
download | pw-12073e3c27b0b571dd340fd7a587c90427042ff3.tar.gz pw-12073e3c27b0b571dd340fd7a587c90427042ff3.tar.bz2 pw-12073e3c27b0b571dd340fd7a587c90427042ff3.zip |
New feature: grep mode with pattern stack.
-rw-r--r-- | pw.1 | 34 | ||||
-rw-r--r-- | pw.c | 121 |
2 files changed, 131 insertions, 24 deletions
@@ -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. @@ -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; |