From: Miklos Vajna <vmiklos@frugalware.org>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org,
Johannes Schindelin <Johannes.Schindelin@gmx.de>,
Olivier Marin <dkr@freesurf.fr>,
Johannes Schindelin <johannes.schindelin@gmx.de>
Subject: [PATCH 11/15] Add strbuf_vaddf(), use it in strbuf_addf(), and add strbuf_initf()
Date: Fri, 27 Jun 2008 18:22:04 +0200 [thread overview]
Message-ID: <7ea320cd49601de0e331777f82528876101fd946.1214581610.git.vmiklos@frugalware.org> (raw)
In-Reply-To: <67035c91a933887c7cc97fa6d3dda9462594d611.1214581610.git.vmiklos@frugalware.org>
In-Reply-To: <cover.1214581610.git.vmiklos@frugalware.org>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
The most common use of addf() was to init a strbuf and addf() right away.
Since it is so common, it makes sense to have a function strbuf_initf() to
wrap both calls into one.
To do that, we implement a (really minimal) vaddf() lookalike to
vsprintf().
At the moment, it only handles %u, %i, %d, %l, %o, %x and %X with size
indicators '<number>', ' <number>' and '0<number>', as well as %c and %s,
the latter with size indicators '.*' in addition to the same size
indicators as for numbers.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
.gitignore | 1 +
Makefile | 4 +-
strbuf.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++------
strbuf.h | 3 +
t/t0000-basic.sh | 8 +++
test-strbuf.c | 17 +++++++
6 files changed, 150 insertions(+), 17 deletions(-)
create mode 100644 test-strbuf.c
diff --git a/.gitignore b/.gitignore
index 4ff2fec..9281395 100644
--- a/.gitignore
+++ b/.gitignore
@@ -151,6 +151,7 @@ test-genrandom
test-match-trees
test-parse-options
test-sha1
+test-strbuf
common-cmds.h
*.tar.gz
*.dsc
diff --git a/Makefile b/Makefile
index 314339d..1b43171 100644
--- a/Makefile
+++ b/Makefile
@@ -1230,7 +1230,7 @@ endif
### Testing rules
-TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X test-parse-options$X
+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X test-absolute-path$X test-parse-options$X test-strbuf$X
all:: $(TEST_PROGRAMS)
@@ -1249,6 +1249,8 @@ test-delta$X: diff-delta.o patch-delta.o
test-parse-options$X: parse-options.o
+test-strbuf$X: strbuf.o
+
.PRECIOUS: $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
test-%$X: test-%.o $(GITLIBS)
diff --git a/strbuf.c b/strbuf.c
index 4aed752..72b3585 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -122,28 +122,130 @@ void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
strbuf_setlen(sb, sb->len + len);
}
+static int number_length(unsigned long number, long base)
+{
+ int length = 1;
+ while (number >= base) {
+ number /= base;
+ length++;
+ }
+ return length;
+}
+
+/*
+ * Only supports %u, %i, %d, %l, %o, %x and %X with size indicators
+ * '<number>', '0<number>', and ' <number>',
+ * as well as %c,
+ * and %s with size indicators '<number>', ' <number>' and '.*'.
+ */
+void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
+{
+ while (*fmt) {
+ char fill = '\0';
+ int size = -1, max_size = -1;
+ char *p = (char *)fmt;
+
+ if (*p != '%' || *(++p) == '%') {
+ strbuf_addch(sb, *p++);
+ fmt = p;
+ continue;
+ }
+ if (*p == ' ' || *p == '0')
+ fill = *p++;
+ if (isdigit(*p))
+ size = (int)strtol(p, &p, 10);
+ else if (!prefixcmp(p, ".*")) {
+ max_size = va_arg(ap, int);
+ p += 2;
+ }
+ switch (*p) {
+ case 's': {
+ const char *s = va_arg(ap, const char *);
+ if (fill) {
+ int len = size - strlen(s);
+ while (len-- > 0)
+ strbuf_addch(sb, fill);
+ }
+ while (*s && max_size--)
+ strbuf_addch(sb, *s++);
+ break;
+ }
+ case 'c':
+ strbuf_addch(sb, va_arg(ap, int));
+ break;
+ case 'u':
+ case 'i':
+ case 'l':
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'X': {
+ int base = *p == 'x' || *p == 'X' ? 16 :
+ *p == 'o' ? 8 : 10;
+ int negative = 0, len;
+ unsigned long number, power;
+
+ if (*p == 'u')
+ number = va_arg(ap, unsigned int);
+ else {
+ long signed_number;
+ if (*p == 'l')
+ signed_number = va_arg(ap, long);
+ else
+ signed_number = va_arg(ap, int);
+ if (signed_number < 0) {
+ negative = 1;
+ number = -signed_number;
+ } else
+ number = signed_number;
+ }
+
+ /* pad */
+ len = number_length(number, base);
+ while (size-- > len + negative)
+ strbuf_addch(sb, fill ? fill : ' ');
+ if (negative)
+ strbuf_addch(sb, '-');
+
+ /* output number */
+ power = 1;
+ while (len-- > 1)
+ power *= base;
+ while (power) {
+ int digit = number / power;
+ strbuf_addch(sb, digit < 10 ? '0' + digit
+ : *p + 'A' - 'X' + digit - 10);
+ number -= digit * power;
+ power /= base;
+ }
+
+ break;
+ }
+ default:
+ /* unknown / invalid format: copy verbatim */
+ strbuf_insert(sb, sb->len, fmt, p - fmt + 1);
+ }
+ fmt = p + (*p != '\0');
+ }
+}
+
void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
{
- int len;
va_list ap;
- if (!strbuf_avail(sb))
- strbuf_grow(sb, 64);
va_start(ap, fmt);
- len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
+ strbuf_vaddf(sb, fmt, ap);
+ va_end(ap);
+}
+
+void strbuf_initf(struct strbuf *sb, const char *fmt, ...)
+{
+ va_list ap;
+
+ strbuf_init(sb, strlen(fmt) + 64);
+ va_start(ap, fmt);
+ strbuf_vaddf(sb, fmt, ap);
va_end(ap);
- if (len < 0)
- die("your vsnprintf is broken");
- if (len > strbuf_avail(sb)) {
- strbuf_grow(sb, len);
- va_start(ap, fmt);
- len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
- va_end(ap);
- if (len > strbuf_avail(sb)) {
- die("this should not happen, your snprintf is broken");
- }
- }
- strbuf_setlen(sb, sb->len + len);
}
void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
diff --git a/strbuf.h b/strbuf.h
index faec229..d7c7aaf 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -106,8 +106,11 @@ extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
+extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list args);
__attribute__((format(printf,2,3)))
extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
+__attribute__((format(printf,2,3)))
+extern void strbuf_initf(struct strbuf *sb, const char *fmt, ...);
extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
/* XXX: if read fails, any partial read is undone */
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 690f80a..7c7ca4c 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -311,6 +311,14 @@ test_expect_success 'absolute path works as expected' '
test "$sym" = "$(test-absolute-path "$dir2/syml")"
'
+test_expect_success 'strbuf_initf() works as expected' '
+
+ eval $(test-strbuf) &&
+ test ! -z "$result" &&
+ test "$result" = "$expect"
+
+'
+
test_expect_success 'very long name in the index handled sanely' '
a=a && # 1
diff --git a/test-strbuf.c b/test-strbuf.c
new file mode 100644
index 0000000..479fa08
--- /dev/null
+++ b/test-strbuf.c
@@ -0,0 +1,17 @@
+#include "cache.h"
+#include "strbuf.h"
+
+int main(int argc, char **argv)
+{
+ struct strbuf buf;
+#define TEST_FORMAT \
+ "'%%%.*s,%x,%05X,%u,%i,% 4d,%3d,%c,%3d'", \
+ 5, "Hello, World!", 27, 27, -1, -1, 1, 5, ':', 1234
+
+ strbuf_initf(&buf, TEST_FORMAT);
+ printf("result=%s\n", buf.buf);
+ printf("expect=" TEST_FORMAT);
+ strbuf_release(&buf);
+
+ return 0;
+}
--
1.5.6
next prev parent reply other threads:[~2008-06-27 16:27 UTC|newest]
Thread overview: 81+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-06-27 16:21 [PATCH 00/15] Build in merge Miklos Vajna
2008-06-27 16:21 ` [PATCH 01/15] Move split_cmdline() to alias.c Miklos Vajna
2008-06-27 16:21 ` [PATCH 02/15] Move commit_list_count() to commit.c Miklos Vajna
2008-06-27 16:21 ` [PATCH 03/15] Move parse-options's skip_prefix() to git-compat-util.h Miklos Vajna
2008-06-27 16:21 ` [PATCH 04/15] Add new test to ensure git-merge handles pull.twohead and pull.octopus Miklos Vajna
2008-06-27 16:21 ` [PATCH 05/15] Move read_cache_unmerged() to read-cache.c Miklos Vajna
2008-06-27 16:21 ` [PATCH 06/15] git-fmt-merge-msg: make it usable from other builtins Miklos Vajna
2008-06-27 16:22 ` [PATCH 07/15] Introduce get_octopus_merge_bases() in commit.c Miklos Vajna
2008-06-27 16:22 ` [PATCH 08/15] Add new test to ensure git-merge handles more than 25 refs Miklos Vajna
2008-06-27 16:22 ` [PATCH 09/15] Introduce get_merge_bases_many() Miklos Vajna
2008-06-27 16:22 ` [PATCH 10/15] Introduce reduce_heads() Miklos Vajna
2008-06-27 16:22 ` Miklos Vajna [this message]
2008-06-27 16:22 ` [PATCH 12/15] strbuf_vaddf(): support %*s, too Miklos Vajna
2008-06-27 16:22 ` [PATCH 13/15] Add new test case to ensure git-merge reduces octopus parents when possible Miklos Vajna
2008-06-27 16:22 ` [PATCH 14/15] Add new test case to ensure git-merge prepends the custom merge message Miklos Vajna
2008-06-27 16:22 ` [PATCH 15/15] Build in merge Miklos Vajna
2008-06-27 17:09 ` Miklos Vajna
2008-06-28 2:00 ` [PATCH 11/15] Add strbuf_vaddf(), use it in strbuf_addf(), and add strbuf_initf() Junio C Hamano
2008-06-28 2:33 ` Miklos Vajna
2008-06-28 2:38 ` [PATCH 13/13] Build in merge Miklos Vajna
2008-06-29 7:46 ` Junio C Hamano
2008-06-29 8:11 ` Jakub Narebski
2008-06-30 1:36 ` Miklos Vajna
2008-06-30 1:39 ` Miklos Vajna
2008-06-30 5:44 ` Junio C Hamano
2008-06-30 17:41 ` Alex Riesen
2008-07-01 2:13 ` Miklos Vajna
2008-07-01 2:22 ` [PATCH 13/14] git-commit-tree: make it usable from other builtins Miklos Vajna
2008-07-01 5:07 ` Johannes Schindelin
2008-07-01 5:50 ` Junio C Hamano
2008-07-01 12:09 ` Miklos Vajna
2008-07-01 2:22 ` [PATCH 14/14] Build in merge Miklos Vajna
2008-07-01 2:37 ` [PATCH 00/14] " Miklos Vajna
2008-07-01 2:37 ` [PATCH 08/14] Add new test to ensure git-merge handles more than 25 refs Miklos Vajna
2008-07-01 2:37 ` [PATCH 13/14] git-commit-tree: make it usable from other builtins Miklos Vajna
2008-07-01 2:37 ` [PATCH 14/14] Build in merge Miklos Vajna
2008-07-01 6:23 ` Junio C Hamano
2008-07-01 12:50 ` Miklos Vajna
2008-07-01 13:18 ` Miklos Vajna
2008-07-01 23:55 ` Junio C Hamano
2008-07-02 7:43 ` Miklos Vajna
2008-07-06 8:50 ` Junio C Hamano
2008-07-06 9:43 ` Junio C Hamano
2008-07-07 17:17 ` Miklos Vajna
2008-07-07 18:15 ` Junio C Hamano
2008-07-07 23:42 ` [PATCH] " Miklos Vajna
2008-07-08 0:32 ` Junio C Hamano
2008-07-08 0:53 ` Junio C Hamano
2008-07-08 1:18 ` Miklos Vajna
2008-07-08 1:00 ` Miklos Vajna
2008-07-08 1:05 ` Junio C Hamano
2008-07-08 1:41 ` Miklos Vajna
2008-07-06 12:38 ` [PATCH 14/14] " Johannes Schindelin
2008-07-06 19:39 ` Junio C Hamano
2008-07-07 17:24 ` [PATCH] " Miklos Vajna
2008-07-07 17:35 ` Miklos Vajna
2008-07-01 7:27 ` [PATCH 14/14] " Junio C Hamano
2008-07-01 12:55 ` Miklos Vajna
2008-06-30 22:44 ` [PATCH 13/13] " Olivier Marin
2008-06-30 22:58 ` Miklos Vajna
2008-06-30 5:40 ` Junio C Hamano
2008-06-30 22:48 ` Miklos Vajna
2008-06-28 17:33 ` [PATCH 11/15] Add strbuf_vaddf(), use it in strbuf_addf(), and add strbuf_initf() Johannes Schindelin
2008-06-29 8:07 ` Junio C Hamano
2008-06-29 13:40 ` Johannes Schindelin
2008-06-29 20:17 ` Alex Riesen
2008-06-29 20:24 ` Junio C Hamano
2008-06-29 20:30 ` Sverre Rabbelier
2008-06-27 17:06 ` [PATCH 08/15] Add new test to ensure git-merge handles more than 25 refs Miklos Vajna
2008-06-29 13:30 ` [PATCH 04/15] Add new test to ensure git-merge handles pull.twohead and pull.octopus Olivier Marin
2008-06-29 14:51 ` [PATCH] " Miklos Vajna
2008-06-29 15:11 ` Miklos Vajna
2008-07-04 16:34 ` [PATCH 04/15] " Mike Ralphson
2008-07-05 0:26 ` Miklos Vajna
2008-07-05 0:32 ` [PATCH] Fix t7601-merge-pull-config.sh on AIX Miklos Vajna
2008-07-05 1:49 ` Junio C Hamano
2008-06-29 14:05 ` [PATCH 01/15] Move split_cmdline() to alias.c Olivier Marin
2008-06-29 14:15 ` Johannes Schindelin
2008-06-29 14:29 ` Olivier Marin
2008-06-29 14:43 ` Johannes Schindelin
2008-06-30 22:51 ` Olivier Marin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=7ea320cd49601de0e331777f82528876101fd946.1214581610.git.vmiklos@frugalware.org \
--to=vmiklos@frugalware.org \
--cc=Johannes.Schindelin@gmx.de \
--cc=dkr@freesurf.fr \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).