git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v11 03/22] strbuf.c: add `strbuf_insertf()` and `strbuf_vinsertf()`

From
Thomas Gummerer <t.gummerer@gmail.com>
Date
Nov 25, 2018, 21:43 UTC
Message-ID
<20181125214353.GI4883@hank.intra.tgummerer.com>
In-Reply-To
<e8d86fae660a79eabcf4764dfa9986282c097242.1542925164.git.ungureanupaulsebastian@gmail.com>
On 11/23, Paul-Sebastian Ungureanu wrote:
Show 26 quoted lines
> Implement `strbuf_insertf()` and `strbuf_vinsertf()` to
> insert data using a printf format string.
> 
> Original-idea-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> Signed-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>
> ---
>  strbuf.c | 36 ++++++++++++++++++++++++++++++++++++
>  strbuf.h |  9 +++++++++
>  2 files changed, 45 insertions(+)
> 
> diff --git a/strbuf.c b/strbuf.c
> index 82e90f1dfe..bfbbdadbf3 100644
> --- a/strbuf.c
> +++ b/strbuf.c
> @@ -249,6 +249,42 @@ void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
>  	strbuf_splice(sb, pos, 0, data, len);
>  }
>  
> +void strbuf_vinsertf(struct strbuf *sb, size_t pos, const char *fmt, va_list ap)
> +{
> +	int len, len2;
> +	char save;
> +	va_list cp;
> +
> +	if (pos > sb->len)
> +		die("`pos' is too far after the end of the buffer");

I was going to ask about translation of this and other messages in 'die()' calls, but I see other messages in strbuf.c are not marked for translation either. It may make sense to mark them all for translation at some point in the future, but having them all untranslated for now makes sense.

In the long run it may even be better to return an error here rather than 'die()'ing, but again this is consistent with the rest of the API, so this wouldn't be a good time to take that on.

> +	va_copy(cp, ap);
> +	len = vsnprintf(sb->buf + sb->len, 0, fmt, cp);

Here we're just getting the length of what we're trying to format (excluding the final NUL). As the second argument is 0, we do not modify the strbuf at this point...

Show 8 quoted lines
> +	va_end(cp);
> +	if (len < 0)
> +		BUG("your vsnprintf is broken (returned %d)", len);
> +	if (!len)
> +		return; /* nothing to do */
> +	if (unsigned_add_overflows(sb->len, len))
> +		die("you want to use way too much memory");
> +	strbuf_grow(sb, len);

... and then we grow the strbuf by the length we previously, which excludes the NUL character, plus one extra character, so even if pos == len we are sure to have enough space in the strbuf ...

> +	memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos);
> +	/* vsnprintf() will append a NUL, overwriting one of our characters */
> +	save = sb->buf[pos + len];
> +	len2 = vsnprintf(sb->buf + pos, sb->alloc - sb->len, fmt, ap);

... and we use vsnprintf to write the formatted string to the beginning of the buffer. sb->alloc - sb->len can be larger than 'len', which is fine as vsnprintf doesn't write anything after the NUL character. And as 'strbuf_grow' adds len + 1 bytes to the strbuf we'll always have enough space for adding the formatted string ...

> +	sb->buf[pos + len] = save;
> +	if (len2 != len)
> +		BUG("your vsnprintf is broken (returns inconsistent lengths)");
> +	strbuf_setlen(sb, sb->len + len);

And finally we set the strbuf to the new length. So all this is just a very roundabout way to say that this function does the right thing according to my reading (and tests).

Show 36 quoted lines
> +}
> +
> +void strbuf_insertf(struct strbuf *sb, size_t pos, const char *fmt, ...)
> +{
> +	va_list ap;
> +	va_start(ap, fmt);
> +	strbuf_vinsertf(sb, pos, fmt, ap);
> +	va_end(ap);
> +}
> +
>  void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
>  {
>  	strbuf_splice(sb, pos, len, "", 0);
> diff --git a/strbuf.h b/strbuf.h
> index be02150df3..8f8fe01e68 100644
> --- a/strbuf.h
> +++ b/strbuf.h
> @@ -244,6 +244,15 @@ void strbuf_addchars(struct strbuf *sb, int c, size_t n);
>   */
>  void strbuf_insert(struct strbuf *sb, size_t pos, const void *, size_t);
>  
> +/**
> + * Insert data to the given position of the buffer giving a printf format
> + * string. The contents will be shifted, not overwritten.
> + */
> +void strbuf_vinsertf(struct strbuf *sb, size_t pos, const char *fmt,
> +		     va_list ap);
> +
> +void strbuf_insertf(struct strbuf *sb, size_t pos, const char *fmt, ...);
> +
>  /**
>   * Remove given amount of data from a given position of the buffer.
>   */
> -- 
> 2.19.1.878.g0482332a22
> 
Previous: Paul-Sebastian UngureanuNext: Johannes Schindelin
Message 5 of 35 in “Convert "git stash" to C builtin”
  1. 00/22 Convert "git stash" to C builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  2. 01/22 sha1-name.c: add `get_oidf()` which acts like `get_oid()`Paul-Sebastian Ungureanu, Nov 22, 2018
  3. 02/22 strbuf.c: add `strbuf_join_argv()`Paul-Sebastian Ungureanu, Nov 22, 2018
  4. 03/22 strbuf.c: add `strbuf_insertf()` and `strbuf_vinsertf()`Paul-Sebastian Ungureanu, Nov 22, 2018
  5. Thomas GummererNov 25, 2018
  6. Johannes SchindelinNov 27, 2018
  7. Thomas GummererNov 27, 2018
  8. 04/22 stash: improve option parsing test coveragePaul-Sebastian Ungureanu, Nov 22, 2018
  9. 05/22 t3903: modernize stylePaul-Sebastian Ungureanu, Nov 22, 2018
  10. 07/22 stash: add tests for `git stash show` configPaul-Sebastian Ungureanu, Nov 22, 2018
  11. 06/22 stash: rename test cases to be more descriptivePaul-Sebastian Ungureanu, Nov 22, 2018
  12. 08/22 stash: mention options in `show` synopsisPaul-Sebastian Ungureanu, Nov 22, 2018
  13. 10/22 stash: convert drop and clear to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  14. 09/22 stash: convert apply to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  15. 11/22 stash: convert branch to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  16. 15/22 stash: convert store to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  17. 13/22 stash: convert list to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  18. 12/22 stash: convert pop to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  19. 16/22 stash: convert create to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  20. 18/22 stash: make push -q quietPaul-Sebastian Ungureanu, Nov 22, 2018
  21. 17/22 stash: convert push to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  22. 19/22 stash: convert save to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  23. 20/22 stash: convert `stash--helper.c` into `stash.c`Paul-Sebastian Ungureanu, Nov 22, 2018
  24. Junio C HamanoNov 26, 2018
  25. Johannes SchindelinNov 27, 2018
  26. Ævar Arnfjörð BjarmasonNov 27, 2018
  27. Johannes SchindelinNov 29, 2018
  28. 21/22 stash: optimize `get_untracked_files()` and `check_changes()`Paul-Sebastian Ungureanu, Nov 22, 2018
  29. 22/22 stash: replace all `write-tree` child processes with API callsPaul-Sebastian Ungureanu, Nov 22, 2018
  30. 14/22 stash: convert show to builtinPaul-Sebastian Ungureanu, Nov 22, 2018
  31. Thomas GummererNov 25, 2018
  32. Junio C HamanoNov 26, 2018
  33. Junio C HamanoNov 26, 2018
  34. Johannes SchindelinNov 29, 2018
  35. Johannes SchindelinNov 29, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.