-
Notifications
You must be signed in to change notification settings - Fork 140
trace2: clean up formatting in perf target format #298
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
trace2: clean up formatting in perf target format #298
Conversation
Truncate/elide very long "filename:linenumber" field. Truncate region and data "category" field if necessary. Adjust overall column widths. Signed-off-by: Jeff Hostetler <[email protected]>
/submit |
Submitted as [email protected] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I offered a couple of suggestions, but they are minor, and I would be fine with the patches as-are.
avail); | ||
} | ||
|
||
strbuf_release(&buf_fl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of initializing, reallocating and then releasing that strbuf
all the time, I would like to suggest this strategy instead:
strbuf_addf(buf, "%s:%d", file, line);
if (buf->len > TR2FMT_PERF_FL_WIDTH)
/* shorten it to the maximum width, prefixing with ... */
strbuf_splice(buf, len, buf->len - (TR2FMT_PERF_FL_WIDTH - 3), "...", 3);
strbuf_release(&buf_fl); | ||
} | ||
|
||
while (buf->len < fl_end_col) | ||
strbuf_addch(buf, ' '); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this instead? It will potentially avoid repeated re-allocations:
if (buf->len < fl_end_col)
strbuf_addchars(&buf, ' ', fl_end_col - buf->len);
strbuf_addf(buf, "%-*s | ", TR2FMT_PERF_CATEGORY_WIDTH, | ||
(category ? category : "")); | ||
strbuf_addf(buf, "%-*.*s | ", TR2FMT_PERF_CATEGORY_WIDTH, | ||
TR2FMT_PERF_CATEGORY_WIDTH, (category ? category : "")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cute. I did not know that you could do that. But I guess the -*
defines a left-aligned column of a certain minimum width, and the .*
defines the "precision" (maximum length for strings), so you essentially fix-width this.
It might be more readable (and less puzzling to the casual reader) to disentangle this, though:
size_t len;
[...]
len = buf->len;
if (category) {
size_t category_len = strlen(category);
strbuf_add(buf, category, category_len < TR2FMT_PERF_CATEGORY_WIDTH ?
category_len : TR2FMT_PERF_CATEGORY_WIDTH);
}
if (buf->len - len < TR2FMT_PERF_CATEGORY_WIDTH)
strbuf_addchars(buf, ' ', TR2FMT_PERF_CATEGORY_WIDTH);
strbuf_addstr(buf, " | ");
At this point, though, it might make sense to add a fixed-width variant:
void strbuf_addstr_fixed_width(struct strbuf *buf, const char *string, size_t width, int pad_character)
{
size_t offset = buf->len, len = strlen(string);
strbuf_add(buf, string, len < width ? len : width);
if (buf->len - offset < width)
strbuf_addchars(buf, pad_character, width - (buf->len - offset));
}
@@ -21,10 +21,10 @@ static struct tr2_dst tr2dst_perf = { TR2_SYSENV_PERF, 0, 0, 0 }; | |||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Jeff Hostetler via GitGitGadget" <[email protected]> writes:
> From: Jeff Hostetler <[email protected]>
>
> Trim leading/trailing whitespace from the command line
> printed in the "start" message in the perf target format.
>
> We use `sq_quote_argv_pretty()` to format the message
> and it adds a leading space to the output. Trim that.
strbuf_trim() not just drops a single leading space, but removes
consecutive spaces from both ends. But the first char after the SP
comes from the first arg, and it can never be a whitespace (as a
payload that begins with a whitespace will be quoted, so it will be
a single quote), and the last char in the buffer would also be
either a closing single quote (if the last argument ends with a
whitespace) or a non whitespace "safe" character, so it is safe to
use strbuf_trim() here.
I wonder if we want to lose the prepending of SP from
sq_quote_argv_pretty(), though:
* run-command.c::trace_run_command() does rely on having SP there,
so the caller needs adjusting if we did so.
* trace.c::trace_argv_vprintf_fl() also needs SP there after the
caller supplied format.
* trace.c::print_command_performance_atexit() expects command_line
begins with the extra SP left by the sq_quote_argv_pretty()
called by the trace_command_performance(); the format string
given to trace_performance_leave() there needs adjusting.
By the way, use of sq_quote_argv_pretty() in builtin/rebase.c on
opts->git_am_opts.argv done in run_specific_rebase() is dubious.
The argv array is made into a single string that safely uses sq,
appropriate to feed a shell. But that string is passed as the
"value" parameter to add_var() helper that expects to receive a raw
value (hence it calls sq_quote_buf() on the value), resulting in a
string that is doubly quoted. I am not sure if that was intended.
In any case, the patch itself obviously look correct.
> Signed-off-by: Jeff Hostetler <[email protected]>
> ---
> trace2/tr2_tgt_perf.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/trace2/tr2_tgt_perf.c b/trace2/tr2_tgt_perf.c
> index 4a9d99218b..ed4e708f28 100644
> --- a/trace2/tr2_tgt_perf.c
> +++ b/trace2/tr2_tgt_perf.c
> @@ -185,6 +185,7 @@ static void fn_start_fl(const char *file, int line,
> struct strbuf buf_payload = STRBUF_INIT;
>
> sq_quote_argv_pretty(&buf_payload, argv);
> + strbuf_trim(&buf_payload);
>
> perf_io_write_fl(file, line, event_name, NULL, &us_elapsed_absolute,
> NULL, NULL, &buf_payload);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Jeff Hostetler wrote (reply to this):
On 8/1/2019 5:34 PM, Junio C Hamano wrote:
> "Jeff Hostetler via GitGitGadget" <[email protected]> writes:
>
>> From: Jeff Hostetler <[email protected]>
>>
>> Trim leading/trailing whitespace from the command line
>> printed in the "start" message in the perf target format.
>>
>> We use `sq_quote_argv_pretty()` to format the message
>> and it adds a leading space to the output. Trim that.
>
> strbuf_trim() not just drops a single leading space, but removes
> consecutive spaces from both ends. But the first char after the SP
> comes from the first arg, and it can never be a whitespace (as a
> payload that begins with a whitespace will be quoted, so it will be
> a single quote), and the last char in the buffer would also be
> either a closing single quote (if the last argument ends with a
> whitespace) or a non whitespace "safe" character, so it is safe to
> use strbuf_trim() here.
>
> I wonder if we want to lose the prepending of SP from
> sq_quote_argv_pretty(), though:
I was wondering about that too, but I didn't want to presume
to know what all of the callers wanted. And didn't want to
slip in such a change last-minute.
I'll re-roll with a new sq_quote_ function that does not
include the leading whitespace and convert/normalize all
of my trace2/* uses to call it instead. This eliminates
the Trace2 code from the larger conversation (and is a
little more efficient than the strbuf_trim()).
Jeff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
Jeff Hostetler <[email protected]> writes:
> On 8/1/2019 5:34 PM, Junio C Hamano wrote:
>> "Jeff Hostetler via GitGitGadget" <[email protected]> writes:
>>
>>> From: Jeff Hostetler <[email protected]>
>>>
>>> Trim leading/trailing whitespace from the command line
>>> printed in the "start" message in the perf target format.
>>>
>>> We use `sq_quote_argv_pretty()` to format the message
>>> and it adds a leading space to the output. Trim that.
>>
>> strbuf_trim() not just drops a single leading space, but removes
>> consecutive spaces from both ends. But the first char after the SP
>> comes from the first arg, and it can never be a whitespace (as a
>> payload that begins with a whitespace will be quoted, so it will be
>> a single quote), and the last char in the buffer would also be
>> either a closing single quote (if the last argument ends with a
>> whitespace) or a non whitespace "safe" character, so it is safe to
>> use strbuf_trim() here.
>>
>> I wonder if we want to lose the prepending of SP from
>> sq_quote_argv_pretty(), though:
>
> I was wondering about that too, but I didn't want to presume
> to know what all of the callers wanted. And didn't want to
> slip in such a change last-minute.
I do not think this topic/discussion is a place to do so, either.
And compensating on the caller's side, like your patch did, is
perfectly fine.
I was more disturbed by potential double quoting in some codepaths
when I did a cursory audit of users of sq_quote_argv_pretty(), and
would think that would be of more importance, though.
On the Git mailing list, Josh Steadmon wrote (reply to this):
|
This branch is now known as |
This patch series was integrated into pu via git@e41408a. |
This patch series was integrated into pu via git@a54d710. |
This patch series was integrated into pu via git@0ddebcb. |
This patch series was integrated into pu via git@d35ac4f. |
This patch series was integrated into pu via git@8812cac. |
This patch series was integrated into pu via git@3e7fcb9. |
d2f7cf3
to
334b07a
Compare
Avoid unecessary trailing whitespace in "region_enter" and "region_leave" messages in perf target format. Signed-off-by: Jeff Hostetler <[email protected]>
Remove an unnecessary "if" block in maybe_add_string_va(). Commit "ad006fe419e trace2: NULL is not allowed for va_list" changed "if (fmt && *fmt && ap)" to just "if (fmt && *fmt)" because it isn't safe to treat 'ap' as a pointer. This made the "if" block following it unnecessary. Signed-off-by: Jeff Hostetler <[email protected]>
Avoid creating unnecessary trailing whitespace in normal target format error messages when the message is omitted. Signed-off-by: Jeff Hostetler <[email protected]>
334b07a
to
d8eebde
Compare
This patch series was integrated into pu via git@bd11aba. |
d8eebde
to
a6e5e7c
Compare
This patch series was integrated into pu via git@6c513b3. |
/submit |
Submitted as [email protected] |
quote.c
Outdated
@@ -94,6 +94,17 @@ void sq_quote_argv_pretty(struct strbuf *dst, const char **argv) | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
"Jeff Hostetler via GitGitGadget" <[email protected]> writes:
> From: Jeff Hostetler <[email protected]>
>
> Create version of sq_quote_argv_pretty() that does not
> insert a leading space before argv[0].
>
> Signed-off-by: Jeff Hostetler <[email protected]>
> ---
> quote.c | 11 +++++++++++
> quote.h | 1 +
> 2 files changed, 12 insertions(+)
I am OK with the basic idea, but I am somewhat unhappy about this
particular patch for two reasons:
- If we were to keep this as a part of proper API in the longer
term, the current sq_quote_argv_pretty() should be rewritten to
use this to avoid repetition (e.g. as long as !!*argv, add a SP
and then call this new thing);
- something_ltrim() sounds as if you munge what is passed to you
and chop off the left end, but that is not what this does.
Now, what is the right name for this new thing? What does it do?
It looks to me that it appends each element of argv[], quoting it as
needed, and with SP in between. So the right name for the family of
these functions should be around "append", which is the primary thing
they do, with "quoted" somewhere.
Having made the primary purpose of the helper clearer leads me to
wonder if "do not add SP before the first element, i.e. argv[0]", is
really what we want. If we always clear the *dst strbuf before
starting to serialize argv[] into it, then the behaviour would make
sense, but we do not---we are "appending".
As long as we are appending, would we be better off doing something
sillily magical like this instead, I have to wonder?
void sq_append_strings_quoted(struct strbuf *buf, const char **av)
{
int i;
for (i = 0; av[i]; i++) {
if (buf->len)
strbuf_addch(buf, ' ');
sq_quote_buf_pretty(buf, argv[0]);
}
}
That is, "if we are appending to an existing string, have SP to
separate the first element from that existing string; treat the
remaining elements the same way (if the buffer is empty, there is no
point adding SP at the beginning)".
I may have found a long-standing bug in sq_quote_buf_pretty(), by
the way. What does it produce when *src is an empty string of
length 0? It does not add anything to dst, but shouldn't we be
adding two single-quotes (i.e. an empty string inside sq pair)?
> diff --git a/quote.c b/quote.c
> index 7f2aa6faa4..7cad8798ac 100644
> --- a/quote.c
> +++ b/quote.c
> @@ -94,6 +94,17 @@ void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
> }
> }
>
> +void sq_quote_argv_pretty_ltrim(struct strbuf *dst, const char **argv)
> +{
> + int i;
> +
> + for (i = 0; argv[i]; i++) {
> + if (i > 0)
> + strbuf_addch(dst, ' ');
> + sq_quote_buf_pretty(dst, argv[i]);
> + }
> +}
> +
> static char *sq_dequote_step(char *arg, char **next)
> {
> char *dst = arg;
> diff --git a/quote.h b/quote.h
> index fb08dc085c..3b3d041a61 100644
> --- a/quote.h
> +++ b/quote.h
> @@ -40,6 +40,7 @@ void sq_quotef(struct strbuf *, const char *fmt, ...);
> */
> void sq_quote_buf_pretty(struct strbuf *, const char *src);
> void sq_quote_argv_pretty(struct strbuf *, const char **argv);
> +void sq_quote_argv_pretty_ltrim(struct strbuf *, const char **argv);
>
> /* This unwraps what sq_quote() produces in place, but returns
> * NULL if the input does not look like what sq_quote would have
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Jeff Hostetler wrote (reply to this):
On 8/8/2019 2:05 PM, Junio C Hamano wrote:
> "Jeff Hostetler via GitGitGadget" <[email protected]> writes:
>
>> From: Jeff Hostetler <[email protected]>
>>
>> Create version of sq_quote_argv_pretty() that does not
>> insert a leading space before argv[0].
>>
>> Signed-off-by: Jeff Hostetler <[email protected]>
>> ---
>> quote.c | 11 +++++++++++
>> quote.h | 1 +
>> 2 files changed, 12 insertions(+)
>
> I am OK with the basic idea, but I am somewhat unhappy about this
> particular patch for two reasons:
>
> - If we were to keep this as a part of proper API in the longer
> term, the current sq_quote_argv_pretty() should be rewritten to
> use this to avoid repetition (e.g. as long as !!*argv, add a SP
> and then call this new thing);
>
> - something_ltrim() sounds as if you munge what is passed to you
> and chop off the left end, but that is not what this does.
>
> Now, what is the right name for this new thing? What does it do?
I struggled with the proper name for this.
And even thought about adding a 3rd arg to the current function to
indicate whether to have the leading SP before argv[0], but wasn't
sure if that was too disruptive.
>
> It looks to me that it appends each element of argv[], quoting it as
> needed, and with SP in between. So the right name for the family of
> these functions should be around "append", which is the primary thing
> they do, with "quoted" somewhere.
>
> Having made the primary purpose of the helper clearer leads me to
> wonder if "do not add SP before the first element, i.e. argv[0]", is
> really what we want. If we always clear the *dst strbuf before
> starting to serialize argv[] into it, then the behaviour would make
> sense, but we do not---we are "appending".
>
> As long as we are appending, would we be better off doing something
> sillily magical like this instead, I have to wonder?
>
> void sq_append_strings_quoted(struct strbuf *buf, const char **av)
> {
> int i;
>
> for (i = 0; av[i]; i++) {
> if (buf->len)
> strbuf_addch(buf, ' ');
> sq_quote_buf_pretty(buf, argv[0]);
> }
> }
>
> That is, "if we are appending to an existing string, have SP to
> separate the first element from that existing string; treat the
> remaining elements the same way (if the buffer is empty, there is no
> point adding SP at the beginning)".
I don't think that would do what we want. We don't know what the
caller's expectations are. In my uses in commits 6/7 and 7/7 I
already added the leading chars I wanted in the strbuf before calling
sq_quote_argv_pretty_ltrim() and assumed the output would be a true
append. For example:
+ strbuf_addf(&buf_payload, "alias:%s argv:[", alias);
+ sq_quote_argv_pretty_ltrim(&buf_payload, argv);
+ strbuf_addch(&buf_payload, ']');
I like your suggestion of putting my new function in the _append_
category. I think I'll add the 3rd arg to this and then it will
be completely specified and I can get rid of the _ltrim suffix.
I'll re-roll this.
>
> I may have found a long-standing bug in sq_quote_buf_pretty(), by
> the way. What does it produce when *src is an empty string of
> length 0? It does not add anything to dst, but shouldn't we be
> adding two single-quotes (i.e. an empty string inside sq pair)?
I would think so. I did a quick grep and most of the calls looked
guarded, so I don't think this is urgent. I'll address this in a
separate commit shortly.
Thanks
Jeff
>
>> diff --git a/quote.c b/quote.c
>> index 7f2aa6faa4..7cad8798ac 100644
>> --- a/quote.c
>> +++ b/quote.c
>> @@ -94,6 +94,17 @@ void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
>> }
>> }
>>
>> +void sq_quote_argv_pretty_ltrim(struct strbuf *dst, const char **argv)
>> +{
>> + int i;
>> +
>> + for (i = 0; argv[i]; i++) {
>> + if (i > 0)
>> + strbuf_addch(dst, ' ');
>> + sq_quote_buf_pretty(dst, argv[i]);
>> + }
>> +}
>> +
>> static char *sq_dequote_step(char *arg, char **next)
>> {
>> char *dst = arg;
>> diff --git a/quote.h b/quote.h
>> index fb08dc085c..3b3d041a61 100644
>> --- a/quote.h
>> +++ b/quote.h
>> @@ -40,6 +40,7 @@ void sq_quotef(struct strbuf *, const char *fmt, ...);
>> */
>> void sq_quote_buf_pretty(struct strbuf *, const char *src);
>> void sq_quote_argv_pretty(struct strbuf *, const char **argv);
>> +void sq_quote_argv_pretty_ltrim(struct strbuf *, const char **argv);
>>
>> /* This unwraps what sq_quote() produces in place, but returns
>> * NULL if the input does not look like what sq_quote would have
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Junio C Hamano wrote (reply to this):
Jeff Hostetler <[email protected]> writes:
>> That is, "if we are appending to an existing string, have SP to
>> separate the first element from that existing string; treat the
>> remaining elements the same way (if the buffer is empty, there is no
>> point adding SP at the beginning)".
>
> I don't think that would do what we want.
I know that there are current callers of quote_argv_pretty that
either (1) expects that it will always get the leading SP for free,
or (2) has to work the unwanted SP around (basically, the places you
changed from quote_argv_pretty to quote_argv_pretty_ltrim in your
series). But I wanted to see if we can come up with a single helper
whose behaviour is easy to explain and understand that both existing
and new callers can adopt---and if the resulting codebase becomes
easy to understand and maintain overall. And if that would give us
the ideal longer term direction.
>> I may have found a long-standing bug in sq_quote_buf_pretty(), by
>> the way. What does it produce when *src is an empty string of
>> length 0? It does not add anything to dst, but shouldn't we be
>> adding two single-quotes (i.e. an empty string inside sq pair)?
>
> I would think so. I did a quick grep and most of the calls looked
> guarded, so I don't think this is urgent. I'll address this in a
> separate commit shortly.
Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, René Scharfe wrote (reply to this):
Am 08.08.19 um 21:04 schrieb Jeff Hostetler:
> On 8/8/2019 2:05 PM, Junio C Hamano wrote:
>> Having made the primary purpose of the helper clearer leads me to
>> wonder if "do not add SP before the first element, i.e. argv[0]", is
>> really what we want.=C2=A0 If we always clear the *dst strbuf before
>> starting to serialize argv[] into it, then the behaviour would make
>> sense, but we do not---we are "appending".
>>
>> As long as we are appending, would we be better off doing something
>> sillily magical like this instead, I have to wonder?
>>
>> =C2=A0=C2=A0=C2=A0=C2=A0void sq_append_strings_quoted(struct strbuf *bu=
f, const char **av)
>> =C2=A0=C2=A0=C2=A0=C2=A0{
>> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 int i;
>>
>> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 for (i =3D 0; av[i]; i++) {
>> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (=
buf->len)
>> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=
=A0=C2=A0=C2=A0=C2=A0 strbuf_addch(buf, ' ');
>> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 sq_q=
uote_buf_pretty(buf, argv[0]);
>> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 }
>> =C2=A0=C2=A0=C2=A0=C2=A0}
>>
>> That is, "if we are appending to an existing string, have SP to
>> separate the first element from that existing string; treat the
>> remaining elements the same way (if the buffer is empty, there is no
>> point adding SP at the beginning)".
>
> I don't think that would do what we want.=C2=A0 We don't know what the
> caller's expectations are.=C2=A0 In my uses in commits 6/7 and 7/7 I
> already added the leading chars I wanted in the strbuf before calling
> sq_quote_argv_pretty_ltrim() and assumed the output would be a true
> append.=C2=A0 For example:
>
> +=C2=A0=C2=A0=C2=A0 strbuf_addf(&buf_payload, "alias:%s argv:[", alias);
> +=C2=A0=C2=A0=C2=A0 sq_quote_argv_pretty_ltrim(&buf_payload, argv);
> +=C2=A0=C2=A0=C2=A0 strbuf_addch(&buf_payload, ']');
>
> I like your suggestion of putting my new function in the _append_
> category.=C2=A0 I think I'll add the 3rd arg to this and then it will
> be completely specified and I can get rid of the _ltrim suffix.
Two observations:
If callers want to add something before a joined delimited list, they
already can with a strbuf_add* call. No need to add that feature to
a function that joins lists.
And repetitions of repetitions (loops) are boring.
Apologies in advance for any coffee stains on your monitor, but
here's how I would start, probably followed by attempts to inline the
functions that become trivial wrappers:
=2D--
quote.c | 18 ++++--------------
strbuf.c | 20 +++++++++++++-------
strbuf.h | 8 ++++++++
3 files changed, 25 insertions(+), 21 deletions(-)
diff --git a/quote.c b/quote.c
index 7f2aa6faa4..f422188852 100644
=2D-- a/quote.c
+++ b/quote.c
@@ -74,24 +74,14 @@ void sq_quotef(struct strbuf *dst, const char *fmt, ..=
.)
void sq_quote_argv(struct strbuf *dst, const char **argv)
{
- int i;
-
- /* Copy into destination buffer. */
- strbuf_grow(dst, 255);
- for (i =3D 0; argv[i]; ++i) {
- strbuf_addch(dst, ' ');
- sq_quote_buf(dst, argv[i]);
- }
+ strbuf_addch(dst, ' ');
+ strbuf_map_join_argv(dst, argv, sq_quote_buf, " ");
}
void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
{
- int i;
-
- for (i =3D 0; argv[i]; i++) {
- strbuf_addch(dst, ' ');
- sq_quote_buf_pretty(dst, argv[i]);
- }
+ strbuf_addch(dst, ' ');
+ strbuf_map_join_argv(dst, argv, sq_quote_buf_pretty, " ");
}
static char *sq_dequote_step(char *arg, char **next)
diff --git a/strbuf.c b/strbuf.c
index d30f916858..d337853b53 100644
=2D-- a/strbuf.c
+++ b/strbuf.c
@@ -304,17 +304,23 @@ void strbuf_addbuf(struct strbuf *sb, const struct s=
trbuf *sb2)
strbuf_setlen(sb, sb->len + sb2->len);
}
+void strbuf_map_join_argv(struct strbuf *sb, const char **argv,
+ void (*fn)(struct strbuf *, const char *),
+ const char *separator)
+{
+ while (*argv) {
+ fn(sb, *argv++);
+ if (*argv)
+ strbuf_addstr(sb, separator);
+ }
+}
+
const char *strbuf_join_argv(struct strbuf *buf,
int argc, const char **argv, char delim)
{
- if (!argc)
- return buf->buf;
+ char separator[] =3D { delim, '\0' };
- strbuf_addstr(buf, *argv);
- while (--argc) {
- strbuf_addch(buf, delim);
- strbuf_addstr(buf, *(++argv));
- }
+ strbuf_map_join_argv(buf, argv, strbuf_addstr, separator);
return buf->buf;
}
diff --git a/strbuf.h b/strbuf.h
index f62278a0be..7adeff94a7 100644
=2D-- a/strbuf.h
+++ b/strbuf.h
@@ -297,6 +297,14 @@ static inline void strbuf_addstr(struct strbuf *sb, c=
onst char *s)
*/
void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
+/**
+ * Apply `fn` to `sb` and each element of the NULL-terminated array
+ * `argv`. Add `separator` between these invocations.
+ */
+void strbuf_map_join_argv(struct strbuf *sb, const char **argv,
+ void (*fn)(struct strbuf *, const char *),
+ const char *separator);
+
/**
* Join the arguments into a buffer. `delim` is put between every
* two arguments.
=2D-
2.22.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, Jeff Hostetler wrote (reply to this):
On 8/8/2019 6:49 PM, René Scharfe wrote:
> Am 08.08.19 um 21:04 schrieb Jeff Hostetler:
>> On 8/8/2019 2:05 PM, Junio C Hamano wrote:
>>> Having made the primary purpose of the helper clearer leads me to
>>> wonder if "do not add SP before the first element, i.e. argv[0]", is
>>> really what we want. If we always clear the *dst strbuf before
>>> starting to serialize argv[] into it, then the behaviour would make
>>> sense, but we do not---we are "appending".
>>>
>>> As long as we are appending, would we be better off doing something
>>> sillily magical like this instead, I have to wonder?
>>>
>>> void sq_append_strings_quoted(struct strbuf *buf, const char **av)
>>> {
>>> int i;
>>>
>>> for (i = 0; av[i]; i++) {
>>> if (buf->len)
>>> strbuf_addch(buf, ' ');
>>> sq_quote_buf_pretty(buf, argv[0]);
>>> }
>>> }
>>>
>>> That is, "if we are appending to an existing string, have SP to
>>> separate the first element from that existing string; treat the
>>> remaining elements the same way (if the buffer is empty, there is no
>>> point adding SP at the beginning)".
>>
>> I don't think that would do what we want. We don't know what the
>> caller's expectations are. In my uses in commits 6/7 and 7/7 I
>> already added the leading chars I wanted in the strbuf before calling
>> sq_quote_argv_pretty_ltrim() and assumed the output would be a true
>> append. For example:
>>
>> + strbuf_addf(&buf_payload, "alias:%s argv:[", alias);
>> + sq_quote_argv_pretty_ltrim(&buf_payload, argv);
>> + strbuf_addch(&buf_payload, ']');
>>
>> I like your suggestion of putting my new function in the _append_
>> category. I think I'll add the 3rd arg to this and then it will
>> be completely specified and I can get rid of the _ltrim suffix.
>
> Two observations:
>
> If callers want to add something before a joined delimited list, they
> already can with a strbuf_add* call. No need to add that feature to
> a function that joins lists.
>
> And repetitions of repetitions (loops) are boring.
>
> Apologies in advance for any coffee stains on your monitor, but
> here's how I would start, probably followed by attempts to inline the
> functions that become trivial wrappers:
Um, yeah, I must say that I didn't expect the conversation to turn to
map-style functions and a change in design styles. I think it would be
better to have that conversation in a different patch series and not mix
it with my trace2 janitoring.
I'm going to push a V3 that does just the minimum to have a sq_ function
that joins the args with a space delimiter (and without the leading
space) and re-write the existing function to call it after adding the
legacy leading space. This will let existing callers continue to work
as is. And they can be converted if/when anyone wants to dig into them.
>
> ---
> quote.c | 18 ++++--------------
> strbuf.c | 20 +++++++++++++-------
> strbuf.h | 8 ++++++++
> 3 files changed, 25 insertions(+), 21 deletions(-)
>
> diff --git a/quote.c b/quote.c
> index 7f2aa6faa4..f422188852 100644
> --- a/quote.c
> +++ b/quote.c
> @@ -74,24 +74,14 @@ void sq_quotef(struct strbuf *dst, const char *fmt, ...)
>
> void sq_quote_argv(struct strbuf *dst, const char **argv)
> {
> - int i;
> -
> - /* Copy into destination buffer. */
> - strbuf_grow(dst, 255);
> - for (i = 0; argv[i]; ++i) {
> - strbuf_addch(dst, ' ');
> - sq_quote_buf(dst, argv[i]);
> - }
> + strbuf_addch(dst, ' ');
> + strbuf_map_join_argv(dst, argv, sq_quote_buf, " ");
> }
>
> void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
> {
> - int i;
> -
> - for (i = 0; argv[i]; i++) {
> - strbuf_addch(dst, ' ');
> - sq_quote_buf_pretty(dst, argv[i]);
> - }
> + strbuf_addch(dst, ' ');
If I'm reading this correctly, this has slightly different behavior
than the original version. Perhaps:
if (argv[0])
strbuf_addch(dst, ' ');
> + strbuf_map_join_argv(dst, argv, sq_quote_buf_pretty, " ");
> }
>
> static char *sq_dequote_step(char *arg, char **next)
> diff --git a/strbuf.c b/strbuf.c
> index d30f916858..d337853b53 100644
> --- a/strbuf.c
> +++ b/strbuf.c
> @@ -304,17 +304,23 @@ void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
> strbuf_setlen(sb, sb->len + sb2->len);
> }
>
> +void strbuf_map_join_argv(struct strbuf *sb, const char **argv,
> + void (*fn)(struct strbuf *, const char *),
> + const char *separator)
> +{
> + while (*argv) {
> + fn(sb, *argv++);
> + if (*argv)
> + strbuf_addstr(sb, separator);
> + }
> +}
> +
> const char *strbuf_join_argv(struct strbuf *buf,
> int argc, const char **argv, char delim)
> {
> - if (!argc)
> - return buf->buf;
> + char separator[] = { delim, '\0' };
>
> - strbuf_addstr(buf, *argv);
> - while (--argc) {
> - strbuf_addch(buf, delim);
> - strbuf_addstr(buf, *(++argv));
> - }
> + strbuf_map_join_argv(buf, argv, strbuf_addstr, separator);
>
> return buf->buf;
> }
> diff --git a/strbuf.h b/strbuf.h
> index f62278a0be..7adeff94a7 100644
> --- a/strbuf.h
> +++ b/strbuf.h
> @@ -297,6 +297,14 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s)
> */
> void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2);
>
> +/**
> + * Apply `fn` to `sb` and each element of the NULL-terminated array
> + * `argv`. Add `separator` between these invocations.
> + */
> +void strbuf_map_join_argv(struct strbuf *sb, const char **argv,
> + void (*fn)(struct strbuf *, const char *),
> + const char *separator);
> +
> /**
> * Join the arguments into a buffer. `delim` is put between every
> * two arguments.
> --
> 2.22.0
>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the Git mailing list, René Scharfe wrote (reply to this):
Am 09.08.19 um 19:13 schrieb Jeff Hostetler:
> On 8/8/2019 6:49 PM, Ren=C3=A9 Scharfe wrote:
>> =C2=A0 void sq_quote_argv_pretty(struct strbuf *dst, const char **argv)
>> =C2=A0 {
>> -=C2=A0=C2=A0=C2=A0 int i;
>> -
>> -=C2=A0=C2=A0=C2=A0 for (i =3D 0; argv[i]; i++) {
>> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 strbuf_addch(dst, ' ');
>> -=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 sq_quote_buf_pretty(dst, ar=
gv[i]);
>> -=C2=A0=C2=A0=C2=A0 }
>> +=C2=A0=C2=A0=C2=A0 strbuf_addch(dst, ' ');
>
> If I'm reading this correctly, this has slightly different behavior
> than the original version.=C2=A0 Perhaps:
>
> =C2=A0=C2=A0=C2=A0=C2=A0if (argv[0])
> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 strbuf_addch(dst, ' ');
Oh, yes, thanks for spotting this.
Ren=C3=A9
This patch series was integrated into pu via git@b7b06b0. |
a6e5e7c
to
14981c7
Compare
This patch series was integrated into pu via git@a6a65d0. |
This patch series was integrated into pu via git@cf9e2b3. |
sq_quote_argv_pretty() builds a "pretty" string from the given argv. It inserts whitespace before each value, rather than just between them, so the resulting string always has a leading space. Lets give callers an option to not have the leading space or have to ltrim() it later. Create sq_append_quote_argv_pretty() to convert an argv into a pretty, quoted if necessary, string with space delimiters and without a leading space. Convert the existing sq_quote_argv_pretty() to use this new routine while preserving the leading space behavior. Signed-off-by: Jeff Hostetler <[email protected]>
This patch series was integrated into pu via git@cb65f8d. |
This patch series was integrated into pu via git@254b316. |
This patch series was integrated into pu via git@bc2aee7. |
This patch series was integrated into pu via git@7c3303c. |
This patch series was integrated into pu via git@a7498a9. |
This patch series was integrated into pu via git@4f54ec5. |
This patch series was integrated into pu via git@729d7c4. |
This patch series was integrated into pu via git@ea69102. |
This patch series was integrated into pu via git@93b8f6c. |
This patch series was integrated into pu via git@c6431d7. |
This patch series was integrated into pu via git@e6c223a. |
This patch series was integrated into pu via git@8fdd1f4. |
This patch series was integrated into pu via git@7afb627. |
This patch series was integrated into pu via git@b7554ed. |
This patch series was integrated into pu via git@6ed1d8f. |
This patch series was integrated into pu via git@405f6ce. |
This patch series was integrated into pu via git@b43b24f. |
This patch series was integrated into next via git@503974a. |
This patch series was integrated into pu via git@93fc876. |
This patch series was integrated into master via git@93fc876. |
Closed via 93fc876. |
V2 of this patch series cleans up some whitespace and column alignment
issues in the trace2 perf and normal formats. It also removes some dead code.