Change how escaping is processed for formats so that ## and # can be

used in styles. Also add a 'w' format modifier for the width. From Chas
J Owens IV in GitHub issue 2389.
This commit is contained in:
nicm
2020-11-09 09:10:10 +00:00
parent 1326529f99
commit 61e55fa50d
3 changed files with 201 additions and 17 deletions

View File

@ -98,6 +98,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_PANES 0x200
#define FORMAT_PRETTY 0x400
#define FORMAT_LENGTH 0x800
#define FORMAT_WIDTH 0x1000
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 10
@ -1671,7 +1672,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
/*
* Modifiers are a ; separated list of the forms:
* l,m,C,b,d,n,t,q,E,T,S,W,P,<,>
* l,m,C,b,d,n,t,w,q,E,T,S,W,P,<,>
* =a
* =/a
* =/a/
@ -1688,7 +1689,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
cp++;
/* Check single character modifiers with no arguments. */
if (strchr("lbdnqETSWP<>", cp[0]) != NULL &&
if (strchr("lbdnqwETSWP<>", cp[0]) != NULL &&
format_is_end(cp[1])) {
format_add_modifier(&list, count, cp, 1, NULL, 0);
cp++;
@ -2184,6 +2185,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
if (errptr != NULL)
width = 0;
break;
case 'w':
modifiers |= FORMAT_WIDTH;
break;
case 'e':
if (fm->argc < 1 || fm->argc > 3)
break;
@ -2456,13 +2460,19 @@ done:
format_log(es, "applied padding width %d: %s", width, value);
}
/* Replace with the length if needed. */
/* Replace with the length or width if needed. */
if (modifiers & FORMAT_LENGTH) {
xasprintf(&new, "%zu", strlen(value));
free(value);
value = new;
format_log(es, "replacing with length: %s", new);
}
if (modifiers & FORMAT_WIDTH) {
xasprintf(&new, "%u", format_width(value));
free(value);
value = new;
format_log(es, "replacing with width: %s", new);
}
/* Expand the buffer and copy in the value. */
valuelen = strlen(value);
@ -2589,8 +2599,30 @@ format_expand1(struct format_expand_state *es, const char *fmt)
break;
fmt += n + 1;
continue;
case '}':
case '#':
/*
* If ##[ (with two or more #s), then it is a style and
* can be left for format_draw to handle.
*/
ptr = fmt;
n = 2;
while (*ptr == '#') {
ptr++;
n++;
}
if (*ptr == '[') {
format_log(es, "found #*%zu[", n);
while (len - off < n + 2) {
buf = xreallocarray(buf, 2, len);
len *= 2;
}
memcpy(buf + off, fmt - 2, n + 1);
off += n + 1;
fmt = ptr + 1;
continue;
}
/* FALLTHROUGH */
case '}':
case ',':
format_log(es, "found #%c", ch);
while (len - off < 2) {