From 5a5b950e8b86606edea8f61c40bf8af28ab4f08b Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 18 Nov 2015 14:13:55 +0000 Subject: [PATCH] Add s/foo/bar/: prefix for formats to substitute bar for foo. --- format.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++---------- tmux.1 | 7 +++++ 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/format.c b/format.c index 04e06fc6..e8d5dd09 100644 --- a/format.c +++ b/format.c @@ -99,6 +99,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) #define FORMAT_TIMESTRING 0x1 #define FORMAT_BASENAME 0x2 #define FORMAT_DIRNAME 0x4 +#define FORMAT_SUBSTITUTE 0x8 /* Entry in format tree. */ struct format_entry { @@ -682,8 +683,9 @@ int format_replace(struct format_tree *ft, const char *key, size_t keylen, char **buf, size_t *len, size_t *off) { - char *copy, *copy0, *endptr, *ptr, *saved, *trimmed, *value; - size_t valuelen; + char *copy, *copy0, *endptr, *ptr, *found, *new, *value; + char *from = NULL, *to = NULL; + size_t valuelen, newlen, fromlen, tolen, used; u_long limit = 0; int modifiers = 0, brackets; @@ -721,6 +723,29 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, modifiers |= FORMAT_TIMESTRING; copy += 2; break; + case 's': + if (copy[1] != '/') + break; + from = copy + 2; + for (copy = from; *copy != '\0' && *copy != '/'; copy++) + /* nothing */; + if (copy[0] != '/' || copy == from) { + copy = copy0; + break; + } + copy[0] = '\0'; + to = copy + 1; + for (copy = to; *copy != '\0' && *copy != '/'; copy++) + /* nothing */; + if (copy[0] != '/' || copy[1] != ':') { + copy = copy0; + break; + } + copy[0] = '\0'; + + modifiers |= FORMAT_SUBSTITUTE; + copy += 2; + break; } /* @@ -734,7 +759,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, *ptr = '\0'; value = ptr + 1; - saved = format_find(ft, copy + 1, modifiers); + found = format_find(ft, copy + 1, modifiers); brackets = 0; for (ptr = ptr + 1; *ptr != '\0'; ptr++) { @@ -748,29 +773,56 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, if (*ptr == '\0') goto fail; - if (saved != NULL && *saved != '\0' && - (saved[0] != '0' || saved[1] != '\0')) { + if (found != NULL && *found != '\0' && + (found[0] != '0' || found[1] != '\0')) { *ptr = '\0'; } else value = ptr + 1; value = format_expand(ft, value); - free(saved); - saved = value; + free(found); } else { - saved = value = format_find(ft, copy, modifiers); + value = format_find(ft, copy, modifiers); if (value == NULL) - saved = value = xstrdup(""); + value = xstrdup(""); + } + + /* Perform substitution if any. */ + if (modifiers & FORMAT_SUBSTITUTE) { + fromlen = strlen(from); + tolen = strlen(to); + + newlen = strlen(value) + 1; + copy = new = xmalloc(newlen); + for (ptr = value; *ptr != '\0'; /* nothing */) { + if (strncmp(ptr, from, fromlen) != 0) { + *new++ = *ptr++; + continue; + } + used = new - copy; + + newlen += tolen; + copy = xrealloc(copy, newlen); + + new = copy + used; + memcpy(new, to, tolen); + + new += tolen; + ptr += fromlen; + } + *new = '\0'; + free(value); + value = copy; } /* Truncate the value if needed. */ if (limit != 0) { - value = trimmed = utf8_trimcstr(value, limit); - free(saved); - saved = trimmed; + new = utf8_trimcstr(value, limit); + free(value); + value = new; } - valuelen = strlen(value); /* Expand the buffer and copy in the value. */ + valuelen = strlen(value); while (*len - *off < valuelen + 1) { *buf = xreallocarray(*buf, 2, *len); *len *= 2; @@ -778,7 +830,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, memcpy(*buf + *off, value, valuelen); *off += valuelen; - free(saved); + free(value); free(copy0); return (0); diff --git a/tmux.1 b/tmux.1 index 3a08c8cd..a22bb3f3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3311,6 +3311,13 @@ prefixes are and .Xr dirname 3 of the variable respectively. +A prefix of the form +.Ql s/foo/bar/: +will substitute +.Ql foo +with +.Ql bar +throughout. .Pp In addition, the first line of a shell command's output may be inserted using .Ql #() .