diff options
-rw-r--r-- | pw.1 | 122 | ||||
-rw-r--r-- | pw.c | 115 |
2 files changed, 175 insertions, 62 deletions
@@ -184,49 +184,107 @@ and also terminate colon mode without executing a command. Colon commands are documented in the COLON COMMANDS section below. -.IP "\fB/\fP\fIpattern\fP, \fB?\fP\fIpattern\fP" -Activate trigger mode if a non-empty +.IP "[\fIpos\fP]\fB/\fP\fIpattern\fP, [\fIpos\fP]\fB?\fP\fIpattern\fP" +Set a trigger if a non-empty .I pattern -is specified, or else cancel trigger mode if an empty pattern is -specified. The +is specified, or else cancel a trigger if an empty pattern is specified. +The .B / -command specifies -.I "head trigger" +command specifies a +.I "head-referenced trigger" mode, whereas .B ? specifies -.I "tail trigger" +.I "tail-referenced trigger" mode. -Under head trigger mode, -the display refreshes only when the most recent line ("head line") -in the FIFO matches the specified -.IR pattern . -The head line is the one which will appear at -the bottom of the display, since newer lines appear at the bottom -and scroll out toward the top. -In head trigger mode, the status string -.BI "TRIG (/" pattern ")" -appears, showing the pattern preceded by a slash. -Under tail trigger mode, -the display refreshes only when the least recent line ("tail line") in the FIFO -matches the specified -.IR pattern . -That line is the one which will appear at -the top of the display. In tail trigger mode, the status string -.BI "TRIG (?" pattern ")" -appears, showing the pattern preceded by a question mark. -The -.I pattern -is interpreted as either an extended regular expression (ERE) -or (BRE) depending on the current setting. + +Under trigger mode, the display is suspended, similarly to suspend mode. +It is only refreshed when data arrives into the FIFO such that the +state of the FIFO then matches certain regular expression patterns. + +A head-referenced trigger is relative to most recently received data +which appears at the bottom of the display. A tail-referenced +trigger is on least-recently received data, relative to the top +of the display. If one or more triggers are set, then trigger +mode is in effect. If all triggers are removed, trigger mode +is canceled. + +Tail-referenced and head-referenced triggers are mutually exclusive. +If a tail-referenced trigger command is successfully executed, +then all head-referenced triggers are removed. Vice versa, a +tail-referenced trigger command cancels all head-referenced triggers. + +If the numeric prefix +.I pos +is omitted, or specified as zero, then it defaults to 1. +The prefix specifies the relative position of the pattern. +A head-referenced trigger's position is relative to the most +recent data in the FIFO, and therefore is effectively a +reverse line number relative to the bottom of the display. +For example +.B /foo +or, equivalently, +.B 1/foo +triggers when the bottom line of the display contains a match for +the expression +.BR foo . +Whereas +.B 3/bar +triggers when the third line from the bottom matches +.BR bar . +To cancel the +.B 3/bar +trigger without canceling the +.B 1/foo +trigger, the command +.B 3/ +can be used: +.B 3/ +with an empty pattern. Inversely, the tail-referenced pattern +positions are from the top of the display. Thus +.B ?foo +or +.B 1?foo +trigger when the top line contains a match for +.BR foo . + +If the value of +.I pos +specifies a line beyond the display range, or a value greater than 100, the +command is ignored. + Trigger patterns saved in a history which may be navigated for recall using the up and down arrow keys or .B Ctrl-P and .BR Ctrl-N . -While the trigger pattern is being edited, the current trigger remains -in effect. Editing a trigger pattern may be canceled with -.BR ESC . +While the trigger pattern is being edited, the current set of +triggers remains in effect. Editing a trigger pattern may be canceled with +.BR ESC , +in which case it is not entered into the history and and the +trigger command isn't executed. The history stores only the patterns, not the +.I pos +prefix or the +.B ? +or +.B / +command. Erroneous patterns, and the patterns of ignored commands +are still entered into the history; empty patterns are not. + +The +.I pattern +of a newly issued command interpreted as either an extended regular +expression (ERE) or (BRE) depending on the current setting. +This is true even if it is recalled from a history entry which had been created +under a different mode. + +In trigger mode, the status string +.B TRIG/ +or +.B TRIG? +is shown followed by the list of triggers in parentheses. +Patterns which have a position other than 1 are preceded by +the position shown in square brackets. .IP "[\fIcount\fP]\fB+\fP" Increases the display size by @@ -23,6 +23,8 @@ #define ESC 27 #define DEL 127 +#define min(a, b) ((a) < (b) ? (a) : (b)) + #ifdef __GNUC__ #define printf_attr(fmtpos, vargpos) __attribute__ ((format (printf, \ fmtpos, vargpos))) @@ -64,8 +66,10 @@ static int regex_flags = 0; static char **snapshot; static int snaplines; -static char *trigpat; -static regex_t trigex; + +#define maxtrig 100 +static char *trigpat[maxtrig]; +static regex_t trigex[maxtrig]; static grep grepstack[maxgrep]; static int ngrep; @@ -296,10 +300,21 @@ static void drawstatus(int columns, unsigned stat, char *cmd) } } - if ((stat & stat_htmode)) - ptr += snprintf(ptr, end - ptr, "TRIG (/%s) ", trigpat); - else if ((stat & stat_ttmode)) - ptr += snprintf(ptr, end - ptr, "TRIG (?%s) ", trigpat); + if ((stat & (stat_htmode | stat_ttmode))) { + ptr += snprintf(ptr, end - ptr, "TRIG%c (", + (stat & stat_htmode) ? '/' : '?'); + for (int i = 0, first = 1; i < maxtrig; i++) { + if (trigpat[i]) { + if (!first) + ptr += snprintf(ptr, end - ptr, ", "); + if (i > 0) + ptr += snprintf(ptr, end - ptr, "[%d]", i + 1); + ptr += snprintf(ptr, end - ptr, "%s", trigpat[i]); + first = 0; + } + } + ptr += snprintf(ptr, end - ptr, ") "); + } if ((stat & stat_susp)) ptr += snprintf(ptr, end - ptr, "SUSPENDED "); @@ -716,17 +731,32 @@ int main(int argc, char **argv) } } if (line) { - 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_ttmode)) { + int lim = min(maxtrig, nlines); + int trig = 1; + for (int i = 0; i < lim; i++) + if (trigpat[i] && regexec(&trigex[i], circbuf[i], 0, NULL, 0) != 0) { + trig = 0; + break; + } + if (trig) stat |= stat_trgrd; + } else if ((stat & stat_htmode)) { + int trig = 1; + for (int j = nlines - 1, i = 0; j >= 0 && i < maxtrig; j--, i++) { + if (trigpat[i] && regexec(&trigex[i], circbuf[j], 0, NULL, 0) != 0) { + trig = 0; + break; + } + } + if (trig) + stat |= stat_trgrd; + } } else { circbuf[nlines++] = line; if ((stat & stat_susp) == 0) { @@ -944,6 +974,8 @@ int main(int argc, char **argv) break; case CR: case ctrl('c'): if (ch == CR) { + unsigned trig = (cmdcount == UINT_MAX || cmdcount == 0 + ? 0 : cmdcount - 1); if (cmdbuf[1]) { unsigned *pnhist = (kbd_state == kbd_colon ? &ncmdhist : &npathist); @@ -960,38 +992,61 @@ int main(int argc, char **argv) } } - if (kbd_state == kbd_trig) { - if (trigpat) { - regfree(&trigex); - dsdrop(trigpat); - trigpat = 0; - } - stat &= ~(stat_htmode | stat_ttmode); - } - if (kbd_state == kbd_colon && cmdbuf[1]) { execute(cmdbuf, &stat); if (cmdbuf[0] != 0) { kbd_state = kbd_result; break; } - } else if (cmdbuf[1]) { + } else if (kbd_state == kbd_trig && (int) trig < maxlines && trig < maxtrig) { int err; - trigpat = dsdup(cmdbuf + 1); - if ((err = regcomp(&trigex, trigpat, - regex_flags | REG_NOSUB))) - { - regerror(err, &trigex, cmdbuf, sizeof cmdbuf); + char *pat = dsdup(cmdbuf + 1); + regex_t regex; + + if (*pat && (err = regcomp(®ex, pat, regex_flags | REG_NOSUB))) { + regerror(err, ®ex, cmdbuf, sizeof cmdbuf); if (columns < (int) sizeof cmdbuf - 1) cmdbuf[columns] = 0; kbd_state = kbd_result; - dsdrop(trigpat); - trigpat = 0; - break; + } else { + if ((cmdbuf[0] == '/' && (stat & stat_ttmode)) || + (cmdbuf[0] == '?' && (stat & stat_htmode))) + { + for (int i = 0; i < maxtrig; i++) { + if (trigpat[i]) { + regfree(&trigex[i]); + dsdrop(trigpat[i]); + trigpat[i] = 0; + } + } + } + + if (trigpat[trig]) { + regfree(&trigex[trig]); + dsdrop(trigpat[trig]); + trigpat[trig] = 0; + } + + if (*pat) { + regfree(®ex); + regcomp(&trigex[trig], pat, regex_flags | REG_NOSUB); + trigpat[trig] = dsdup(pat); + } + } + dsdrop(pat); + } + + if (kbd_state == kbd_trig) { + stat &= ~(stat_htmode | stat_ttmode); + for (int i = 0; i < maxtrig; i++) { + if (trigpat[i]) { + stat |= (cmdbuf[0] == '/' ? stat_htmode : stat_ttmode); + break; + } } - stat |= (cmdbuf[0] == '/' ? stat_htmode : stat_ttmode); } } + kbd_state = kbd_cmd; curcmd = 0; cmdcount = UINT_MAX; |