hirc

IRC client
Log | Files | Refs

commit 51d6c520b6f00e2f1015ed6b70278a80bc389cbd
parent 4b0f888f0c4b802051ceaff3cb1b6606972617be
Author: hhvn <dev@hhvn.uk>
Date:   Wed,  8 Dec 2021 18:03:25 +0000

commands.c config.c struct.h: /grep

Diffstat:
Mcommands.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mconfig.c | 10++++++++++
Mstruct.h | 11++++++-----
3 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/commands.c b/commands.c @@ -4,6 +4,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <regex.h> #include <pwd.h> #include <sys/types.h> #include "hirc.h" @@ -95,6 +96,14 @@ struct Command commands[] = { {"echo", command_echo, { "usage: /echo ...", "Print temporarily to selected buffer.", NULL}}, + {"grep", command_grep, { + "usage: /grep [-iE] [regex]", + "Search selected buffer", + " -i: case insensitive", + " -E: posix extended regex", + "If no argument supplied, clears previous search", + "Searches are also cleared after selecting another buffer", + "See also config variables: regex.extended and regex.icase", NULL}}, {NULL, NULL}, }; @@ -631,6 +640,67 @@ command_echo(struct Server *server, char *str) { hist_format(selected.history, Activity_none, HIST_SHOW|HIST_TMP, "SELF_UI :%s", str); } +static +void +command_grep(struct Server *server, char *str) { + struct History *p; + regex_t re; + int regopt = 0, ret; + char errbuf[1024]; + enum { opt_extended, opt_icase }; + static struct CommandOpts opts[] = { + {"E", CMD_NARG, opt_extended}, + {"i", CMD_NARG, opt_icase}, + {NULL, 0, 0}, + }; + + hist_purgeopt(selected.history, HIST_GREP); + windows[Win_main].refresh = 1; + if (!str) { + return; + } + + while ((ret = command_getopt(&str, opts)) != opt_done) { + switch (ret) { + case opt_error: + return; + case opt_extended: + regopt |= REG_EXTENDED; + break; + case opt_icase: + regopt |= REG_ICASE; + break; + } + } + + if (config_getl("regex.extended")) + regopt |= REG_EXTENDED; + if (config_getl("regex.icase")) + regopt |= REG_ICASE; + + if ((ret = regcomp(&re, str, regopt)) != 0) { + regerror(ret, &re, errbuf, sizeof(errbuf)); + regfree(&re); + ui_error("unable to compile regex '%s': %s", str, errbuf); + return; + } + + hist_format(selected.history, Activity_none, HIST_SHOW|HIST_TMP|HIST_GREP, "SELF_GREP_START :%s", str); + + /* Get oldest, but don't set p to NULL */ + for (p = selected.history->history; p && p->next; p = p->next); + + /* Traverse until we hit a message generated by us */ + for (; p && !(p->options & HIST_GREP); p = p->prev) { + /* TODO: matching ui_format result by default, + * option for matching raw */ + if (regexec(&re, p->raw, 0, NULL, 0) == 0) + hist_add(selected.history, p->from, p->raw, p->params, p->activity, p->timestamp, p->options | HIST_GREP); + } + + hist_format(selected.history, Activity_none, HIST_SHOW|HIST_TMP|HIST_GREP, "SELF_GREP_END :end of /grep command"); +} + int command_getopt(char **str, struct CommandOpts *opts) { char *opt; diff --git a/config.c b/config.c @@ -85,6 +85,16 @@ struct Config config[] = { .description = { "Maximum reconnect interval in seconds.", "See reconnect.interval", NULL}}, + {"regex.extended", 1, Val_bool, + .num = 0, + .numhandle = NULL, + .description = { + "Use POSIX extended regex at all times.", NULL}}, + {"regex.icase", 1, Val_bool, + .num = 0, + .numhandle = NULL, + .description = { + "Use case insensitive regex at all times.", NULL}}, {"nickcolour.self", 1, Val_colour, .num = 90, .numhandle = config_nickcolour_self, diff --git a/struct.h b/struct.h @@ -32,11 +32,12 @@ enum Activity { }; enum HistOpt { - HIST_SHOW = 1, /* show in buffer */ - HIST_LOG = 2, /* log to server->logfd */ - HIST_MAIN = 4, /* copy to &main_buf */ - HIST_SELF = 8, /* from = self */ - HIST_TMP = 16, /* purge later */ + HIST_SHOW = 1, /* show in buffer */ + HIST_LOG = 2, /* log to server->logfd */ + HIST_MAIN = 4, /* copy to &main_buf */ + HIST_SELF = 8, /* from = self */ + HIST_TMP = 16, /* purge later */ + HIST_GREP = 32, /* generated by /grep */ HIST_DFL = HIST_SHOW|HIST_LOG };