aboutsummaryrefslogtreecommitdiff
path: root/format.c
diff options
context:
space:
mode:
authornicm <nicm>2019-06-13 19:46:00 +0000
committernicm <nicm>2019-06-13 19:46:00 +0000
commit3e72e98e3bdf3e814d6d20060247bb5f5dc859bb (patch)
tree8610823f2b11740c8079b86875bda970f901668a /format.c
parent7e6a26cc9d857ffc53fdb2395aa5413ff1865f9e (diff)
downloadrtmux-3e72e98e3bdf3e814d6d20060247bb5f5dc859bb.tar.gz
rtmux-3e72e98e3bdf3e814d6d20060247bb5f5dc859bb.tar.bz2
rtmux-3e72e98e3bdf3e814d6d20060247bb5f5dc859bb.zip
Add regular expression support for the format search, match and
substitute modifiers.
Diffstat (limited to 'format.c')
-rw-r--r--format.c110
1 files changed, 67 insertions, 43 deletions
diff --git a/format.c b/format.c
index a2174e8c..c2a911f8 100644
--- a/format.c
+++ b/format.c
@@ -23,6 +23,7 @@
#include <errno.h>
#include <fnmatch.h>
#include <libgen.h>
+#include <regex.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@@ -1247,7 +1248,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
cp++;
/* Check single character modifiers with no arguments. */
- if (strchr("lmCbdtqETSWP<>", cp[0]) != NULL &&
+ if (strchr("lbdtqETSWP<>", cp[0]) != NULL &&
format_is_end(cp[1])) {
format_add_modifier(&list, count, cp, 1, NULL, 0);
cp++;
@@ -1268,7 +1269,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
}
/* Now try single character with arguments. */
- if (strchr("s=", cp[0]) == NULL)
+ if (strchr("mCs=", cp[0]) == NULL)
break;
c = cp[0];
@@ -1329,39 +1330,67 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
return list;
}
-/* Perform substitution in string. */
+/* Match against an fnmatch(3) pattern or regular expression. */
static char *
-format_substitute(const char *source, const char *from, const char *to)
+format_match(struct format_modifier *fm, const char *pattern, const char *text)
{
- char *copy, *new;
- const char *cp;
- size_t fromlen, tolen, newlen, used;
-
- fromlen = strlen(from);
- tolen = strlen(to);
-
- newlen = strlen(source) + 1;
- copy = new = xmalloc(newlen);
-
- for (cp = source; *cp != '\0'; /* nothing */) {
- if (strncmp(cp, from, fromlen) != 0) {
- *new++ = *cp++;
- continue;
+ const char *s = "";
+ regex_t r;
+ int flags = 0;
+
+ if (fm->argc >= 1)
+ s = fm->argv[0];
+ if (strchr(s, 'r') == NULL) {
+ if (strchr(s, 'i') != NULL)
+ flags |= FNM_CASEFOLD;
+ if (fnmatch(pattern, text, flags) != 0)
+ return (xstrdup("0"));
+ } else {
+ flags = REG_EXTENDED|REG_NOSUB;
+ if (strchr(s, 'i') != NULL)
+ flags |= REG_ICASE;
+ if (regcomp(&r, pattern, flags) != 0)
+ return (xstrdup("0"));
+ if (regexec(&r, text, 0, NULL, 0) != 0) {
+ regfree(&r);
+ return (xstrdup("0"));
}
- used = new - copy;
-
- newlen += tolen;
- copy = xrealloc(copy, newlen);
+ regfree(&r);
+ }
+ return (xstrdup("1"));
+}
- new = copy + used;
- memcpy(new, to, tolen);
+/* Perform substitution in string. */
+static char *
+format_sub(struct format_modifier *fm, const char *text, const char *pattern,
+ const char *with)
+{
+ char *value;
+ int flags = REG_EXTENDED;
+
+ if (fm->argc >= 3 && strchr(fm->argv[2], 'i') != NULL)
+ flags |= REG_ICASE;
+ value = regsub(pattern, with, text, flags);
+ if (value == NULL)
+ return (xstrdup(text));
+ return (value);
+}
- new += tolen;
- cp += fromlen;
+/* Search inside pane. */
+static char *
+format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
+{
+ int ignore = 0, regex = 0;
+ char *value;
+
+ if (fm->argc >= 1) {
+ if (strchr(fm->argv[0], 'i') != NULL)
+ ignore = 1;
+ if (strchr(fm->argv[0], 'r') != NULL)
+ regex = 1;
}
-
- *new = '\0';
- return (copy);
+ xasprintf(&value, "%u", window_pane_search(wp, s, regex, ignore));
+ return (value);
}
/* Loop over sessions. */
@@ -1506,11 +1535,10 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
char *copy0, *condition, *found, *new;
char *value, *left, *right;
size_t valuelen;
- int modifiers = 0, limit = 0;
+ int modifiers = 0, limit = 0, j;
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
struct format_modifier *sub = NULL;
u_int i, count;
- int j;
/* Make a copy of the key. */
copy = copy0 = xstrndup(key, keylen);
@@ -1537,18 +1565,18 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
search = fm;
break;
case 's':
- if (fm->argc != 2)
+ if (fm->argc < 2)
break;
sub = fm;
break;
case '=':
- if (fm->argc != 1 && fm->argc != 2)
+ if (fm->argc < 1)
break;
limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
&errptr);
if (errptr != NULL)
limit = 0;
- if (fm->argc == 2 && fm->argv[1] != NULL)
+ if (fm->argc >= 2 && fm->argv[1] != NULL)
marker = fm->argv[1];
break;
case 'l':
@@ -1619,7 +1647,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
value = xstrdup("0");
} else {
format_log(ft, "search '%s' pane %%%u", copy, wp->id);
- xasprintf(&value, "%u", window_pane_search(wp, copy));
+ value = format_search(fm, wp, copy);
}
} else if (cmp != NULL) {
/* Comparison of left and right. */
@@ -1671,12 +1699,8 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
value = xstrdup("1");
else
value = xstrdup("0");
- } else if (strcmp(cmp->modifier, "m") == 0) {
- if (fnmatch(left, right, 0) == 0)
- value = xstrdup("1");
- else
- value = xstrdup("0");
- }
+ } else if (strcmp(cmp->modifier, "m") == 0)
+ value = format_match(fm, left, right);
free(right);
free(left);
@@ -1754,8 +1778,8 @@ done:
/* Perform substitution if any. */
if (sub != NULL) {
- new = format_substitute(value, sub->argv[0], sub->argv[1]);
- format_log(ft, "substituted '%s' to '%s: %s", sub->argv[0],
+ new = format_sub(sub, value, sub->argv[0], sub->argv[1]);
+ format_log(ft, "substituted '%s' to '%s': %s", sub->argv[0],
sub->argv[1], new);
free(value);
value = new;