{"thread":{"id":"9314","subject":"[PATCH 1/5] Add test case for basic commit functionality.","startedAt":"2007-07-30T21:28:42Z","lastAt":"2007-07-31T22:01:19Z","messageCount":19,"participants":["Kristian Høgsberg","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"49144","messageId":"11858309261111-git-send-email-krh@redhat.com","threadId":"9314","inReplyTo":null,"subject":"[PATCH 1/5] Add test case for basic commit functionality.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-30T21:28:42Z","receivedAt":"2007-07-30T21:28:42Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"Signed-off-by: Kristian Høgsberg <krh@redhat.com>\n---\n t/t7501-commit.sh |  126 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 126 insertions(+), 0 deletions(-)\n create mode 100644 t/t7501-commit.sh\n\ndiff --git a/t/t7501-commit.sh b/t/t7501-commit.sh\nnew file mode 100644\nindex 0000000..eba19da\n--- /dev/null\n+++ b/t/t7501-commit.sh\n@@ -0,0 +1,126 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>\n+#\n+\n+# FIXME: Test the various index usages, -i and -o, test reflog,\n+# signoff, hooks\n+\n+test_description='git-commit'\n+. ./test-lib.sh\n+\n+# Pick a date so we get consistent commits. 7/7/07 means good luck!\n+export GIT_AUTHOR_DATE=\"July 7, 2007\"\n+export GIT_COMMITTER_DATE=\"July 7, 2007\"\n+\n+echo \"bongo bongo\" >file\n+test_expect_success \\\n+\t\"initial status\" \\\n+\t\"git-add file && \\\n+\t git-status | grep 'Initial commit'\"\n+\n+test_expect_failure \\\n+\t\"fail initial amend\" \\\n+\t\"git-commit -m initial --amend\"\n+\n+test_expect_success \\\n+\t\"initial commit\" \\\n+\t\"git-commit -m initial\"\n+\n+test_expect_failure \\\n+\t\"testing nothing to commit\" \\\n+\t\"git-commit -m initial\"\n+\n+echo \"bongo bongo bongo\" >file\n+\n+test_expect_success \\\n+\t\"next commit\" \\\n+\t\"git-commit -m next -a\"\n+\n+echo \"more bongo: bongo bongo bongo bongo\" >file\n+\n+test_expect_failure \\\n+\t\"commit message from non-existing file\" \\\n+\t\"git-commit -F gah -a\"\n+\n+cat >msg <<EOF\n+\t\t\n+\n+  \n+Signed-off-by: hula\n+EOF\n+test_expect_failure \\\n+\t\"empty commit message\" \\\n+\t\"git-commit -F msg -a\"\n+\n+echo \"this is the commit message, coming from a file\" >msg\n+test_expect_success \\\n+\t\"commit message from file\" \\\n+\t\"git-commit -F msg -a\"\n+\n+cat >editor <<\\EOF\n+#!/bin/sh\n+sed -i -e \"s/a file/an amend commit/g\" $1\n+EOF\n+chmod 755 editor\n+\n+test_expect_success \\\n+\t\"amend commit\" \\\n+\t\"VISUAL=./editor git-commit --amend\"\n+\n+echo \"enough with the bongos\" >file\n+test_expect_failure \\\n+\t\"passing --amend and -F\" \\\n+\t\"git-commit -F msg --amend .\"\n+\n+test_expect_success \\\n+\t\"using message from other commit\" \\\n+\t\"git-commit -C HEAD^ .\"\n+\n+cat >editor <<\\EOF\n+#!/bin/sh\n+sed -i -e \"s/amend/older/g\" $1\n+EOF\n+chmod 755 editor\n+\n+echo \"hula hula\" >file\n+test_expect_success \\\n+\t\"editing message from other commit\" \\\n+\t\"VISUAL=./editor git-commit -c HEAD^ -a\"\n+\n+echo \"silly new contents\" >file\n+test_expect_success \\\n+\t\"message from stdin\" \\\n+\t\"echo commit message from stdin | git-commit -F - -a\"\n+\n+echo \"gak\" >file\n+test_expect_success \\\n+\t\"overriding author from command line\" \\\n+\t\"git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a\"\n+\n+test_expect_success \\\n+\t\"interactive add\" \\\n+\t\"echo 7 | git-commit --interactive | grep 'What now'\"\n+\n+test_expect_success \\\n+\t\"showing committed revisions\" \\\n+\t\"git-rev-list HEAD >current\"\n+\n+# We could just check the head sha1, but checking each commit makes it\n+# easier to isolate bugs.\n+\n+cat >expected <<\\EOF\n+b19013342b676054179a1685d62b07f56b354331\n+763fd16cd476920986129b09672915be44847d90\n+b97ce6debb52cbb541d798ce4c2cefa3c9f20332\n+720cebf2e443885c6325a0a602ddb9922376452c\n+19db513255cc049feee9c107e60297a48c6b0df4\n+4cd324560cd9dcac18f17bac227b17238ad458f9\n+821776fc6a0699927268feb5e157d245cdcd102a\n+EOF\n+\n+test_expect_success \\\n+    'validate git-rev-list output.' \\\n+    'diff current expected'\n+\n+test_done\n-- \n1.5.2.GIT\n"},{"id":"49148","messageId":"11858309311728-git-send-email-krh@redhat.com","threadId":"9314","inReplyTo":"11858309261111-git-send-email-krh@redhat.com","subject":"[PATCH 2/5] Enable wt-status output to a given FILE pointer.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-30T21:28:43Z","receivedAt":"2007-07-30T21:28:43Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"From: Kristian Høgsberg <krh@redhat.com>\n\nStill defaults to stdout, but you can now override wt_status.fp after\ncalling wt_status_prepare().\n\nSigned-off-by: Kristian Høgsberg <krh@redhat.com>\n---\n color.c     |   18 ++++++------\n color.h     |    4 +-\n wt-status.c |   85 ++++++++++++++++++++++++++++++----------------------------\n wt-status.h |    3 ++\n 4 files changed, 58 insertions(+), 52 deletions(-)\n\ndiff --git a/color.c b/color.c\nindex 09d82ee..124ba33 100644\n--- a/color.c\n+++ b/color.c\n@@ -135,39 +135,39 @@ int git_config_colorbool(const char *var, const char *value)\n \treturn git_config_bool(var, value);\n }\n \n-static int color_vprintf(const char *color, const char *fmt,\n+static int color_vfprintf(FILE *fp, const char *color, const char *fmt,\n \t\tva_list args, const char *trail)\n {\n \tint r = 0;\n \n \tif (*color)\n-\t\tr += printf(\"%s\", color);\n-\tr += vprintf(fmt, args);\n+\t\tr += fprintf(fp, \"%s\", color);\n+\tr += vfprintf(fp, fmt, args);\n \tif (*color)\n-\t\tr += printf(\"%s\", COLOR_RESET);\n+\t\tr += fprintf(fp, \"%s\", COLOR_RESET);\n \tif (trail)\n-\t\tr += printf(\"%s\", trail);\n+\t\tr += fprintf(fp, \"%s\", trail);\n \treturn r;\n }\n \n \n \n-int color_printf(const char *color, const char *fmt, ...)\n+int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)\n {\n \tva_list args;\n \tint r;\n \tva_start(args, fmt);\n-\tr = color_vprintf(color, fmt, args, NULL);\n+\tr = color_vfprintf(fp, color, fmt, args, NULL);\n \tva_end(args);\n \treturn r;\n }\n \n-int color_printf_ln(const char *color, const char *fmt, ...)\n+int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)\n {\n \tva_list args;\n \tint r;\n \tva_start(args, fmt);\n-\tr = color_vprintf(color, fmt, args, \"\\n\");\n+\tr = color_vfprintf(fp, color, fmt, args, \"\\n\");\n \tva_end(args);\n \treturn r;\n }\ndiff --git a/color.h b/color.h\nindex 88bb8ff..6809800 100644\n--- a/color.h\n+++ b/color.h\n@@ -6,7 +6,7 @@\n \n int git_config_colorbool(const char *var, const char *value);\n void color_parse(const char *var, const char *value, char *dst);\n-int color_printf(const char *color, const char *fmt, ...);\n-int color_printf_ln(const char *color, const char *fmt, ...);\n+int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);\n+int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);\n \n #endif /* COLOR_H */\ndiff --git a/wt-status.c b/wt-status.c\nindex 5205420..65a7259 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -52,31 +52,33 @@ void wt_status_prepare(struct wt_status *s)\n \thead = resolve_ref(\"HEAD\", sha1, 0, NULL);\n \ts->branch = head ? xstrdup(head) : NULL;\n \ts->reference = \"HEAD\";\n+\ts->fp = stdout;\n }\n \n-static void wt_status_print_cached_header(const char *reference)\n+static void wt_status_print_cached_header(struct wt_status *s)\n {\n \tconst char *c = color(WT_STATUS_HEADER);\n-\tcolor_printf_ln(c, \"# Changes to be committed:\");\n-\tif (reference) {\n-\t\tcolor_printf_ln(c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", reference);\n+\tcolor_fprintf_ln(s->fp, c, \"# Changes to be committed:\");\n+\tif (s->reference) {\n+\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git reset %s <file>...\\\" to unstage)\", s->reference);\n \t} else {\n-\t\tcolor_printf_ln(c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n+\t\tcolor_fprintf_ln(s->fp, c, \"#   (use \\\"git rm --cached <file>...\\\" to unstage)\");\n \t}\n-\tcolor_printf_ln(c, \"#\");\n+\tcolor_fprintf_ln(s->fp, c, \"#\");\n }\n \n-static void wt_status_print_header(const char *main, const char *sub)\n+static void wt_status_print_header(struct wt_status *s,\n+\t\t\t\t   const char *main, const char *sub)\n {\n \tconst char *c = color(WT_STATUS_HEADER);\n-\tcolor_printf_ln(c, \"# %s:\", main);\n-\tcolor_printf_ln(c, \"#   (%s)\", sub);\n-\tcolor_printf_ln(c, \"#\");\n+\tcolor_fprintf_ln(s->fp, c, \"# %s:\", main);\n+\tcolor_fprintf_ln(s->fp, c, \"#   (%s)\", sub);\n+\tcolor_fprintf_ln(s->fp, c, \"#\");\n }\n \n-static void wt_status_print_trailer(void)\n+static void wt_status_print_trailer(struct wt_status *s)\n {\n-\tcolor_printf_ln(color(WT_STATUS_HEADER), \"#\");\n+\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"#\");\n }\n \n static const char *quote_crlf(const char *in, char *buf, size_t sz)\n@@ -108,7 +110,8 @@ static const char *quote_crlf(const char *in, char *buf, size_t sz)\n \treturn ret;\n }\n \n-static void wt_status_print_filepair(int t, struct diff_filepair *p)\n+static void wt_status_print_filepair(struct wt_status *s,\n+\t\t\t\t     int t, struct diff_filepair *p)\n {\n \tconst char *c = color(t);\n \tconst char *one, *two;\n@@ -117,36 +120,36 @@ static void wt_status_print_filepair(int t, struct diff_filepair *p)\n \tone = quote_crlf(p->one->path, onebuf, sizeof(onebuf));\n \ttwo = quote_crlf(p->two->path, twobuf, sizeof(twobuf));\n \n-\tcolor_printf(color(WT_STATUS_HEADER), \"#\\t\");\n+\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n \tswitch (p->status) {\n \tcase DIFF_STATUS_ADDED:\n-\t\tcolor_printf(c, \"new file:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, \"new file:   %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_COPIED:\n-\t\tcolor_printf(c, \"copied:     %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, \"copied:     %s -> %s\", one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_DELETED:\n-\t\tcolor_printf(c, \"deleted:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, \"deleted:    %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_MODIFIED:\n-\t\tcolor_printf(c, \"modified:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, \"modified:   %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_RENAMED:\n-\t\tcolor_printf(c, \"renamed:    %s -> %s\", one, two);\n+\t\tcolor_fprintf(s->fp, c, \"renamed:    %s -> %s\", one, two);\n \t\tbreak;\n \tcase DIFF_STATUS_TYPE_CHANGED:\n-\t\tcolor_printf(c, \"typechange: %s\", one);\n+\t\tcolor_fprintf(s->fp, c, \"typechange: %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNKNOWN:\n-\t\tcolor_printf(c, \"unknown:    %s\", one);\n+\t\tcolor_fprintf(s->fp, c, \"unknown:    %s\", one);\n \t\tbreak;\n \tcase DIFF_STATUS_UNMERGED:\n-\t\tcolor_printf(c, \"unmerged:   %s\", one);\n+\t\tcolor_fprintf(s->fp, c, \"unmerged:   %s\", one);\n \t\tbreak;\n \tdefault:\n \t\tdie(\"bug: unhandled diff status %c\", p->status);\n \t}\n-\tprintf(\"\\n\");\n+\tfprintf(s->fp, \"\\n\");\n }\n \n static void wt_status_print_updated_cb(struct diff_queue_struct *q,\n@@ -160,14 +163,14 @@ static void wt_status_print_updated_cb(struct diff_queue_struct *q,\n \t\tif (q->queue[i]->status == 'U')\n \t\t\tcontinue;\n \t\tif (!shown_header) {\n-\t\t\twt_status_print_cached_header(s->reference);\n+\t\t\twt_status_print_cached_header(s);\n \t\t\ts->commitable = 1;\n \t\t\tshown_header = 1;\n \t\t}\n-\t\twt_status_print_filepair(WT_STATUS_UPDATED, q->queue[i]);\n+\t\twt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);\n \t}\n \tif (shown_header)\n-\t\twt_status_print_trailer();\n+\t\twt_status_print_trailer(s);\n }\n \n static void wt_status_print_changed_cb(struct diff_queue_struct *q,\n@@ -184,12 +187,12 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,\n \t\t\t\tmsg = use_add_rm_msg;\n \t\t\t\tbreak;\n \t\t\t}\n-\t\twt_status_print_header(\"Changed but not updated\", msg);\n+\t\twt_status_print_header(s, \"Changed but not updated\", msg);\n \t}\n \tfor (i = 0; i < q->nr; i++)\n-\t\twt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);\n+\t\twt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);\n \tif (q->nr)\n-\t\twt_status_print_trailer();\n+\t\twt_status_print_trailer(s);\n }\n \n static void wt_read_cache(struct wt_status *s)\n@@ -206,16 +209,16 @@ static void wt_status_print_initial(struct wt_status *s)\n \twt_read_cache(s);\n \tif (active_nr) {\n \t\ts->commitable = 1;\n-\t\twt_status_print_cached_header(NULL);\n+\t\twt_status_print_cached_header(s);\n \t}\n \tfor (i = 0; i < active_nr; i++) {\n-\t\tcolor_printf(color(WT_STATUS_HEADER), \"#\\t\");\n-\t\tcolor_printf_ln(color(WT_STATUS_UPDATED), \"new file: %s\",\n+\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_UPDATED), \"new file: %s\",\n \t\t\t\tquote_crlf(active_cache[i]->name,\n \t\t\t\t\t   buf, sizeof(buf)));\n \t}\n \tif (active_nr)\n-\t\twt_status_print_trailer();\n+\t\twt_status_print_trailer(s);\n }\n \n static void wt_status_print_updated(struct wt_status *s)\n@@ -281,12 +284,12 @@ static void wt_status_print_untracked(struct wt_status *s)\n \t\t}\n \t\tif (!shown_header) {\n \t\t\ts->workdir_untracked = 1;\n-\t\t\twt_status_print_header(\"Untracked files\",\n+\t\t\twt_status_print_header(s, \"Untracked files\",\n \t\t\t\t\t       use_add_to_include_msg);\n \t\t\tshown_header = 1;\n \t\t}\n-\t\tcolor_printf(color(WT_STATUS_HEADER), \"#\\t\");\n-\t\tcolor_printf_ln(color(WT_STATUS_UNTRACKED), \"%.*s\",\n+\t\tcolor_fprintf(s->fp, color(WT_STATUS_HEADER), \"#\\t\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), \"%.*s\",\n \t\t\t\tent->len, ent->name);\n \t}\n }\n@@ -316,14 +319,14 @@ void wt_status_print(struct wt_status *s)\n \t\t\tbranch_name = \"\";\n \t\t\ton_what = \"Not currently on any branch.\";\n \t\t}\n-\t\tcolor_printf_ln(color(WT_STATUS_HEADER),\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER),\n \t\t\t\"# %s%s\", on_what, branch_name);\n \t}\n \n \tif (s->is_initial) {\n-\t\tcolor_printf_ln(color(WT_STATUS_HEADER), \"#\");\n-\t\tcolor_printf_ln(color(WT_STATUS_HEADER), \"# Initial commit\");\n-\t\tcolor_printf_ln(color(WT_STATUS_HEADER), \"#\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"#\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"# Initial commit\");\n+\t\tcolor_fprintf_ln(s->fp, color(WT_STATUS_HEADER), \"#\");\n \t\twt_status_print_initial(s);\n \t}\n \telse {\n@@ -337,7 +340,7 @@ void wt_status_print(struct wt_status *s)\n \t\twt_status_print_verbose(s);\n \tif (!s->commitable) {\n \t\tif (s->amend)\n-\t\t\tprintf(\"# No changes\\n\");\n+\t\t\tfprintf(s->fp, \"# No changes\\n\");\n \t\telse if (s->workdir_dirty)\n \t\t\tprintf(\"no changes added to commit (use \\\"git add\\\" and/or \\\"git commit -a\\\")\\n\");\n \t\telse if (s->workdir_untracked)\ndiff --git a/wt-status.h b/wt-status.h\nindex cfea4ae..4f3a615 100644\n--- a/wt-status.h\n+++ b/wt-status.h\n@@ -1,6 +1,8 @@\n #ifndef STATUS_H\n #define STATUS_H\n \n+#include <stdio.h>\n+\n enum color_wt_status {\n \tWT_STATUS_HEADER,\n \tWT_STATUS_UPDATED,\n@@ -19,6 +21,7 @@ struct wt_status {\n \tint commitable;\n \tint workdir_dirty;\n \tint workdir_untracked;\n+\tFILE *fp;\n };\n \n int git_status_config(const char *var, const char *value);\n-- \n1.5.2.GIT\n"},{"id":"49147","messageId":"11858309322006-git-send-email-krh@redhat.com","threadId":"9314","inReplyTo":"11858309311728-git-send-email-krh@redhat.com","subject":"[PATCH 3/5] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-30T21:28:44Z","receivedAt":"2007-07-30T21:28:44Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"From: Kristian Høgsberg <krh@redhat.com>\n\nAlso, expose strbuf_add() and strbuf_add_char() to add raw data to the buffer.\n\nSigned-off-by: Kristian Høgsberg <krh@redhat.com>\n---\n strbuf.c |   37 +++++++++++++++++++++++++++++++------\n strbuf.h |    3 +++\n 2 files changed, 34 insertions(+), 6 deletions(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex e33d06b..a0539db 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -11,16 +11,28 @@ static void strbuf_begin(struct strbuf *sb) {\n \tstrbuf_init(sb);\n }\n \n-static void inline strbuf_add(struct strbuf *sb, int ch) {\n-\tif (sb->alloc <= sb->len) {\n+static void inline strbuf_grow(struct strbuf *sb, size_t extra)\n+{\n+\twhile (sb->alloc < sb->len + extra)\n \t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n-\t\tsb->buf = xrealloc(sb->buf, sb->alloc);\n-\t}\n+\tsb->buf = xrealloc(sb->buf, sb->alloc);\n+}\n+\n+void strbuf_add(struct strbuf *sb, const char *data, size_t len)\n+{\n+\tstrbuf_grow(sb, len);\n+\tmemcpy(sb->buf + sb->len, data, len);\n+\tsb->len += len;\n+}\n+\n+void strbuf_add_char(struct strbuf *sb, int ch)\n+{\n+\tstrbuf_grow(sb, 1);\n \tsb->buf[sb->len++] = ch;\n }\n \n static void strbuf_end(struct strbuf *sb) {\n-\tstrbuf_add(sb, 0);\n+\tstrbuf_add_char(sb, 0);\n }\n \n void read_line(struct strbuf *sb, FILE *fp, int term) {\n@@ -33,9 +45,22 @@ void read_line(struct strbuf *sb, FILE *fp, int term) {\n \twhile ((ch = fgetc(fp)) != EOF) {\n \t\tif (ch == term)\n \t\t\tbreak;\n-\t\tstrbuf_add(sb, ch);\n+\t\tstrbuf_add_char(sb, ch);\n \t}\n \tif (ch == EOF && sb->len == 0)\n \t\tsb->eof = 1;\n \tstrbuf_end(sb);\n }\n+\n+void strbuf_printf(struct strbuf *sb, const char *fmt, ...)\n+{\n+\tchar one_line[2048];\n+\tva_list args;\n+\tint len;\n+\n+\tva_start(args, fmt);\n+\tlen = vsnprintf(one_line, sizeof(one_line), fmt, args);\n+\tva_end(args);\n+\tstrbuf_add(sb, one_line, len);\n+}\n+\ndiff --git a/strbuf.h b/strbuf.h\nindex 74cc012..1e5d09e 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -9,5 +9,8 @@ struct strbuf {\n \n extern void strbuf_init(struct strbuf *);\n extern void read_line(struct strbuf *, FILE *, int);\n+extern void strbuf_add(struct strbuf *sb, const char *data, size_t len);\n+extern void strbuf_add_char(struct strbuf *sb, int ch);\n+extern void strbuf_printf(struct strbuf *sb, const char *fmt, ...);\n \n #endif /* STRBUF_H */\n-- \n1.5.2.GIT\n"},{"id":"49145","messageId":"11858309322915-git-send-email-krh@redhat.com","threadId":"9314","inReplyTo":"11858309322006-git-send-email-krh@redhat.com","subject":"[PATCH 4/5] Make builtin-commit-tree use a strbuf instead of hand-rolled realloc buffer.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-30T21:28:45Z","receivedAt":"2007-07-30T21:28:45Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"From: Kristian Høgsberg <krh@redhat.com>\n\nWith the new strbuf_printf() function we can now just a strbuf for\nbuilding up the commit object.\n\nSigned-off-by: Kristian Høgsberg <krh@redhat.com>\n---\n builtin-commit-tree.c |   57 +++++++++++-------------------------------------\n 1 files changed, 13 insertions(+), 44 deletions(-)\n\ndiff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\nindex ccbcbe3..72884eb 100644\n--- a/builtin-commit-tree.c\n+++ b/builtin-commit-tree.c\n@@ -8,42 +8,13 @@\n #include \"tree.h\"\n #include \"builtin.h\"\n #include \"utf8.h\"\n+#include \"strbuf.h\"\n \n #define BLOCKING (1ul << 14)\n \n /*\n  * FIXME! Share the code with \"write-tree.c\"\n  */\n-static void init_buffer(char **bufp, unsigned int *sizep)\n-{\n-\t*bufp = xmalloc(BLOCKING);\n-\t*sizep = 0;\n-}\n-\n-static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)\n-{\n-\tchar one_line[2048];\n-\tva_list args;\n-\tint len;\n-\tunsigned long alloc, size, newsize;\n-\tchar *buf;\n-\n-\tva_start(args, fmt);\n-\tlen = vsnprintf(one_line, sizeof(one_line), fmt, args);\n-\tva_end(args);\n-\tsize = *sizep;\n-\tnewsize = size + len + 1;\n-\talloc = (size + 32767) & ~32767;\n-\tbuf = *bufp;\n-\tif (newsize > alloc) {\n-\t\talloc = (newsize + 32767) & ~32767;\n-\t\tbuf = xrealloc(buf, alloc);\n-\t\t*bufp = buf;\n-\t}\n-\t*sizep = newsize - 1;\n-\tmemcpy(buf + size, one_line, len);\n-}\n-\n static void check_valid(unsigned char *sha1, enum object_type expect)\n {\n \tenum object_type type = sha1_object_info(sha1, NULL);\n@@ -88,8 +59,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \tunsigned char tree_sha1[20];\n \tunsigned char commit_sha1[20];\n \tchar comment[1000];\n-\tchar *buffer;\n-\tunsigned int size;\n+\tstruct strbuf sb;\n \tint encoding_is_utf8;\n \n \tgit_config(git_default_config);\n@@ -118,8 +88,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t/* Not having i18n.commitencoding is the same as having utf-8 */\n \tencoding_is_utf8 = is_encoding_utf8(git_commit_encoding);\n \n-\tinit_buffer(&buffer, &size);\n-\tadd_buffer(&buffer, &size, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n+\tstrbuf_init(&sb);\n+\tstrbuf_printf(&sb, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n \n \t/*\n \t * NOTE! This ordering means that the same exact tree merged with a\n@@ -127,26 +97,25 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t * if everything else stays the same.\n \t */\n \tfor (i = 0; i < parents; i++)\n-\t\tadd_buffer(&buffer, &size, \"parent %s\\n\", sha1_to_hex(parent_sha1[i]));\n+\t\tstrbuf_printf(&sb, \"parent %s\\n\", sha1_to_hex(parent_sha1[i]));\n \n \t/* Person/date information */\n-\tadd_buffer(&buffer, &size, \"author %s\\n\", git_author_info(1));\n-\tadd_buffer(&buffer, &size, \"committer %s\\n\", git_committer_info(1));\n+\tstrbuf_printf(&sb, \"author %s\\n\", git_author_info(1));\n+\tstrbuf_printf(&sb, \"committer %s\\n\", git_committer_info(1));\n \tif (!encoding_is_utf8)\n-\t\tadd_buffer(&buffer, &size,\n-\t\t\t\t\"encoding %s\\n\", git_commit_encoding);\n-\tadd_buffer(&buffer, &size, \"\\n\");\n+\t\tstrbuf_printf(&sb, \"encoding %s\\n\", git_commit_encoding);\n+\tstrbuf_printf(&sb, \"\\n\");\n \n \t/* And add the comment */\n \twhile (fgets(comment, sizeof(comment), stdin) != NULL)\n-\t\tadd_buffer(&buffer, &size, \"%s\", comment);\n+\t\tstrbuf_printf(&sb, \"%s\", comment);\n \n \t/* And check the encoding */\n-\tbuffer[size] = '\\0';\n-\tif (encoding_is_utf8 && !is_utf8(buffer))\n+\tstrbuf_add_char(&sb, '\\0');\n+\tif (encoding_is_utf8 && !is_utf8(sb.buf))\n \t\tfprintf(stderr, commit_utf8_warn);\n \n-\tif (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {\n+\tif (!write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1)) {\n \t\tprintf(\"%s\\n\", sha1_to_hex(commit_sha1));\n \t\treturn 0;\n \t}\n-- \n1.5.2.GIT\n"},{"id":"49146","messageId":"11858309332705-git-send-email-krh@redhat.com","threadId":"9314","inReplyTo":"11858309322915-git-send-email-krh@redhat.com","subject":"[PATCH 5/5] Split out the actual commit creation from the option parsing etc.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-30T21:28:46Z","receivedAt":"2007-07-30T21:28:46Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"From: Kristian Høgsberg <krh@redhat.com>\n\nThe functionality is available inside git through the function\ncreate_commit().\n\nSigned-off-by: Kristian Høgsberg <krh@redhat.com>\n---\n builtin-commit-tree.c |   96 ++++++++++++++++++++++++++++++------------------\n commit.h              |    7 ++++\n 2 files changed, 67 insertions(+), 36 deletions(-)\n\ndiff --git a/builtin-commit-tree.c b/builtin-commit-tree.c\nindex 72884eb..e20f0b4 100644\n--- a/builtin-commit-tree.c\n+++ b/builtin-commit-tree.c\n@@ -52,15 +52,59 @@ static const char commit_utf8_warn[] =\n \"You may want to amend it after fixing the message, or set the config\\n\"\n \"variable i18n.commitencoding to the encoding your project uses.\\n\";\n \n+const unsigned char *\n+create_commit(const unsigned char *tree_sha1,\n+\t      unsigned char parent_sha1[][20], int parents,\n+\t      const char *author_info, const char *committer_info,\n+\t      const char *message, int length)\n+{\n+\tstatic unsigned char commit_sha1[20];\n+\tint encoding_is_utf8, i;\n+\tstruct strbuf sb;\n+\n+\t/* Not having i18n.commitencoding is the same as having utf-8 */\n+\tencoding_is_utf8 = is_encoding_utf8(git_commit_encoding);\n+\n+\tstrbuf_init(&sb);\n+\tstrbuf_printf(&sb, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n+\n+\t/*\n+\t * NOTE! This ordering means that the same exact tree merged with a\n+\t * different order of parents will be a _different_ changeset even\n+\t * if everything else stays the same.\n+\t */\n+\tfor (i = 0; i < parents; i++)\n+\t\tstrbuf_printf(&sb, \"parent %s\\n\", sha1_to_hex(parent_sha1[i]));\n+\n+\t/* Person/date information */\n+\tstrbuf_printf(&sb, \"author %s\\n\", author_info);\n+\tstrbuf_printf(&sb, \"committer %s\\n\", committer_info);\n+\tif (!encoding_is_utf8)\n+\t\tstrbuf_printf(&sb, \"encoding %s\\n\", git_commit_encoding);\n+\tstrbuf_printf(&sb, \"\\n\");\n+\n+\t/* And add the comment */\n+\tstrbuf_add(&sb, message, length);\n+\n+\t/* And check the encoding */\n+\tstrbuf_add_char(&sb, '\\0');\n+\tif (encoding_is_utf8 && !is_utf8(sb.buf))\n+\t\tfprintf(stderr, commit_utf8_warn);\n+\n+\tif (!write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1))\n+\t\treturn commit_sha1;\n+\n+\treturn NULL;\n+}\n+\n int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n \tint parents = 0;\n \tunsigned char tree_sha1[20];\n-\tunsigned char commit_sha1[20];\n-\tchar comment[1000];\n-\tstruct strbuf sb;\n-\tint encoding_is_utf8;\n+\tchar *buffer;\n+\tunsigned long len;\n+\tconst unsigned char *commit_sha1;\n \n \tgit_config(git_default_config);\n \n@@ -85,40 +129,20 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t\t\tparents++;\n \t}\n \n-\t/* Not having i18n.commitencoding is the same as having utf-8 */\n-\tencoding_is_utf8 = is_encoding_utf8(git_commit_encoding);\n+\tbuffer = NULL;\n+\tif (read_fd(0, &buffer, &len))\n+\t\tdie(\"Could not read commit message from standard input\");\n \n-\tstrbuf_init(&sb);\n-\tstrbuf_printf(&sb, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n+\tcommit_sha1 = create_commit(tree_sha1,\n+\t\t\t\t    parent_sha1, parents,\n+\t\t\t\t    xstrdup(git_author_info(1)),\n+\t\t\t\t    xstrdup(git_committer_info(1)),\n+\t\t\t\t    buffer, len);\n \n-\t/*\n-\t * NOTE! This ordering means that the same exact tree merged with a\n-\t * different order of parents will be a _different_ changeset even\n-\t * if everything else stays the same.\n-\t */\n-\tfor (i = 0; i < parents; i++)\n-\t\tstrbuf_printf(&sb, \"parent %s\\n\", sha1_to_hex(parent_sha1[i]));\n-\n-\t/* Person/date information */\n-\tstrbuf_printf(&sb, \"author %s\\n\", git_author_info(1));\n-\tstrbuf_printf(&sb, \"committer %s\\n\", git_committer_info(1));\n-\tif (!encoding_is_utf8)\n-\t\tstrbuf_printf(&sb, \"encoding %s\\n\", git_commit_encoding);\n-\tstrbuf_printf(&sb, \"\\n\");\n-\n-\t/* And add the comment */\n-\twhile (fgets(comment, sizeof(comment), stdin) != NULL)\n-\t\tstrbuf_printf(&sb, \"%s\", comment);\n+\tif (!commit_sha1)\n+\t\treturn 1;\n \n-\t/* And check the encoding */\n-\tstrbuf_add_char(&sb, '\\0');\n-\tif (encoding_is_utf8 && !is_utf8(sb.buf))\n-\t\tfprintf(stderr, commit_utf8_warn);\n+\tprintf(\"%s\\n\", sha1_to_hex(commit_sha1));\n \n-\tif (!write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1)) {\n-\t\tprintf(\"%s\\n\", sha1_to_hex(commit_sha1));\n-\t\treturn 0;\n-\t}\n-\telse\n-\t\treturn 1;\n+\treturn 0;\n }\ndiff --git a/commit.h b/commit.h\nindex 467872e..9f640ba 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -122,4 +122,11 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,\n \t\tint depth, int shallow_flag, int not_shallow_flag);\n \n int in_merge_bases(struct commit *, struct commit **, int);\n+\n+extern const unsigned char *\n+create_commit(const unsigned char *tree_sha1,\n+\t      unsigned char parent_sha1[][20], int parents,\n+\t      const char *author_info, const char *committer_info,\n+\t      const char *message, int length);\n+\n #endif /* COMMIT_H */\n-- \n1.5.2.GIT\n"},{"id":"49190","messageId":"7vodhtgq99.fsf@assigned-by-dhcp.cox.net","threadId":"9314","inReplyTo":"11858309261111-git-send-email-krh@redhat.com","subject":"Re: [PATCH 1/5] Add test case for basic commit functionality.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-31T04:18:26Z","receivedAt":"2007-07-31T04:18:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kristian Høgsberg <krh@redhat.com> writes:\n\n> +# Pick a date so we get consistent commits. 7/7/07 means good luck!\n> +export GIT_AUTHOR_DATE=\"July 7, 2007\"\n> +export GIT_COMMITTER_DATE=\"July 7, 2007\"\n\nOther scripts use test_tick for consistent commits; just to let\nyou know, the above is as good if you intend to use only one\ntimestamp.\n\n> +echo \"bongo bongo\" >file\n> +test_expect_success \\\n> +\t\"initial status\" \\\n> +\t\"git-add file && \\\n> +\t git-status | grep 'Initial commit'\"\n\nWe tend to prefer to have the \"create testfile\" part also in the\ntest.\n\n> +test_expect_failure \\\n> +\t\"fail initial amend\" \\\n> +\t\"git-commit -m initial --amend\"\n\nDoes it fail because it is initial, or because these two\noptions, \"-m <msg>\" and \"--amend\", are incompatible?\n\n> +echo \"bongo bongo bongo\" >file\n\nDitto.\n\n> +cat >msg <<EOF\n> +\t\t\n> +\n> +  \n> +Signed-off-by: hula\n> +EOF\n\n... except <<here text are left outside of test_expect_success\nbecause there were reports that some shells cannot grok here\ntext in eval correctly.\n"},{"id":"49192","messageId":"7vhcnlgpeo.fsf@assigned-by-dhcp.cox.net","threadId":"9314","inReplyTo":"11858309322006-git-send-email-krh@redhat.com","subject":"Re: [PATCH 3/5] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-31T04:36:47Z","receivedAt":"2007-07-31T04:36:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kristian Høgsberg <krh@redhat.com> writes:\n\n> +static void inline strbuf_grow(struct strbuf *sb, size_t extra)\n> +{\n> +\twhile (sb->alloc < sb->len + extra)\n>  \t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n> +\tsb->buf = xrealloc(sb->buf, sb->alloc);\n> +}\n\nSomehow this while () loop to compute the growth factor bothers\nme but that is probably a minor detail.\n\n> +void strbuf_printf(struct strbuf *sb, const char *fmt, ...)\n> +{\n> +\tchar one_line[2048];\n> +\tva_list args;\n> +\tint len;\n\nSuch a nice abstraction so far, and then at the highest level of\ncallchain we have this hardcoded limit?\n"},{"id":"49193","messageId":"7vd4y9gp9q.fsf@assigned-by-dhcp.cox.net","threadId":"9314","inReplyTo":"11858309322915-git-send-email-krh@redhat.com","subject":"Re: [PATCH 4/5] Make builtin-commit-tree use a strbuf instead of hand-rolled realloc buffer.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-31T04:39:45Z","receivedAt":"2007-07-31T04:39:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Very nice.\n"},{"id":"49194","messageId":"7v8x8xgp3s.fsf@assigned-by-dhcp.cox.net","threadId":"9314","inReplyTo":"11858309332705-git-send-email-krh@redhat.com","subject":"Re: [PATCH 5/5] Split out the actual commit creation from the option parsing etc.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-31T04:43:19Z","receivedAt":"2007-07-31T04:43:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kristian Høgsberg <krh@redhat.com> writes:\n\n> @@ -85,40 +129,20 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n>  \t\t\tparents++;\n>  \t}\n>  \n> -\t/* Not having i18n.commitencoding is the same as having utf-8 */\n> -\tencoding_is_utf8 = is_encoding_utf8(git_commit_encoding);\n> +\tbuffer = NULL;\n> +\tif (read_fd(0, &buffer, &len))\n> +\t\tdie(\"Could not read commit message from standard input\");\n>  \n> -\tstrbuf_init(&sb);\n> -\tstrbuf_printf(&sb, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n> +\tcommit_sha1 = create_commit(tree_sha1,\n> +\t\t\t\t    parent_sha1, parents,\n> +\t\t\t\t    xstrdup(git_author_info(1)),\n> +\t\t\t\t    xstrdup(git_committer_info(1)),\n> +\t\t\t\t    buffer, len);\n\nHmph, the series was so nice so far, but here we have a few new\nleak, presumably so small per process invocation that we do not\ncare about?\n"},{"id":"49224","messageId":"1185891109.11086.28.camel@hinata.boston.redhat.com","threadId":"9314","inReplyTo":"7v8x8xgp3s.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 5/5] Split out the actual commit creation from the option parsing etc.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-31T14:11:49Z","receivedAt":"2007-07-31T14:11:49Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Mon, 2007-07-30 at 21:43 -0700, Junio C Hamano wrote:\n> Kristian Høgsberg <krh@redhat.com> writes:\n> \n> > @@ -85,40 +129,20 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n> >  \t\t\tparents++;\n> >  \t}\n> >  \n> > -\t/* Not having i18n.commitencoding is the same as having utf-8 */\n> > -\tencoding_is_utf8 = is_encoding_utf8(git_commit_encoding);\n> > +\tbuffer = NULL;\n> > +\tif (read_fd(0, &buffer, &len))\n> > +\t\tdie(\"Could not read commit message from standard input\");\n> >  \n> > -\tstrbuf_init(&sb);\n> > -\tstrbuf_printf(&sb, \"tree %s\\n\", sha1_to_hex(tree_sha1));\n> > +\tcommit_sha1 = create_commit(tree_sha1,\n> > +\t\t\t\t    parent_sha1, parents,\n> > +\t\t\t\t    xstrdup(git_author_info(1)),\n> > +\t\t\t\t    xstrdup(git_committer_info(1)),\n> > +\t\t\t\t    buffer, len);\n> \n> Hmph, the series was so nice so far, but here we have a few new\n> leak, presumably so small per process invocation that we do not\n> care about?\n\nThere's number of buffers that don't get freed: the strbuf, the commit\nmessage buffer, and the strdup'ed author and committer info.  All the\nleaks are not critical since the process exits immediately.  As for the\nstrbuf leak, I was thinking about renaming strbuf_begin to strbuf_reset\nand making it public[1], which will then be used for freeing up strbuf\nmemory.  The message buffer leak should be fixed by adding a\nstrbuf_read_fd() that just reads it straight into the strbuf.  The\nxstrdup's are necessary because fmt_ident uses a static buffer (thanks,\ntest case :).  We could add rotating static buffers for fmt_ident like\ngit_path and avoid the strdups, but again, the leaks are not critical.\n\nKristian\n\n[1] strbuf_begin() is a good name the way it's used in strbuf.c where\nit's balanced by strbuf_end(), but as a general purpose reset function\nit's better name strbuf_reset(), I think\n"},{"id":"49226","messageId":"1185891786.11086.40.camel@hinata.boston.redhat.com","threadId":"9314","inReplyTo":"7vhcnlgpeo.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 3/5] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-31T14:23:05Z","receivedAt":"2007-07-31T14:23:05Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Mon, 2007-07-30 at 21:36 -0700, Junio C Hamano wrote:\n> Kristian Høgsberg <krh@redhat.com> writes:\n> \n> > +static void inline strbuf_grow(struct strbuf *sb, size_t extra)\n> > +{\n> > +\twhile (sb->alloc < sb->len + extra)\n> >  \t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n> > +\tsb->buf = xrealloc(sb->buf, sb->alloc);\n> > +}\n> \n> Somehow this while () loop to compute the growth factor bothers\n> me but that is probably a minor detail.\n\nThink of it as a more efficient way of adding one character at a time :)\nAnd it's logarithmic in the number of extra bytes.  By the way, I\nnormally just double the size in these cases, which gives you amortized\nlinear performance for adding to the buffer.  What's behind the * 3 / 2\nidea?\n\n> > +void strbuf_printf(struct strbuf *sb, const char *fmt, ...)\n> > +{\n> > +\tchar one_line[2048];\n> > +\tva_list args;\n> > +\tint len;\n> \n> Such a nice abstraction so far, and then at the highest level of\n> callchain we have this hardcoded limit?\n\nYeah, I know, it sucks.  I'd like to just run vsnprintf with a 0-sized\nbuffer to get the length, and then grow the buffer by that much, but\nthat's not very portable as far as I know.  Another approach is to just\nvsnprintf into the one_line buffer and copy it into the strbuf if it\ndoesn't overflow.  If it does overflow, grow the buffer with that amount\nand vsnprintf into the buffer.  I don't think that's portable either,\nsince vsnprintf can't be relied upon to return the number of characters\nit would have printed.  One thing that would work, but is much more\ninvolved is to lift the vsnprintf implementation from something like\nglib.\n\nSo, I dunno... given the options, I opted for a simple solution with\nsome limitations.  Given how many other functions in git work on a fixed\nsized static buffer (for example, the fmt_ident case mentioned in\nanother email), I wouldn't think this is a problem\n\nKristian\n"},{"id":"49225","messageId":"1185892031.11086.43.camel@hinata.boston.redhat.com","threadId":"9314","inReplyTo":"7vodhtgq99.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 1/5] Add test case for basic commit functionality.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-31T14:27:11Z","receivedAt":"2007-07-31T14:27:11Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Mon, 2007-07-30 at 21:18 -0700, Junio C Hamano wrote:\n> Kristian Høgsberg <krh@redhat.com> writes:\n> \n> > +# Pick a date so we get consistent commits. 7/7/07 means good luck!\n> > +export GIT_AUTHOR_DATE=\"July 7, 2007\"\n> > +export GIT_COMMITTER_DATE=\"July 7, 2007\"\n> \n> Other scripts use test_tick for consistent commits; just to let\n> you know, the above is as good if you intend to use only one\n> timestamp.\n\nOk, cool, I'll send out an updated test case.\n\nKristian\n"},{"id":"49228","messageId":"Pine.LNX.4.64.0707311554220.14781@racer.site","threadId":"9314","inReplyTo":"1185891786.11086.40.camel@hinata.boston.redhat.com","subject":"Re: [PATCH 3/5] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-31T14:55:25Z","receivedAt":"2007-07-31T14:55:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 31 Jul 2007, Kristian H?gsberg wrote:\n\n> On Mon, 2007-07-30 at 21:36 -0700, Junio C Hamano wrote:\n> > Kristian Høgsberg <krh@redhat.com> writes:\n> > \n> > > +static void inline strbuf_grow(struct strbuf *sb, size_t extra)\n> > > +{\n> > > +\twhile (sb->alloc < sb->len + extra)\n> > >  \t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n> > > +\tsb->buf = xrealloc(sb->buf, sb->alloc);\n> > > +}\n> > \n> > Somehow this while () loop to compute the growth factor bothers\n> > me but that is probably a minor detail.\n> \n> Think of it as a more efficient way of adding one character at a time :)\n> And it's logarithmic in the number of extra bytes.  By the way, I\n> normally just double the size in these cases, which gives you amortized\n> linear performance for adding to the buffer.  What's behind the * 3 / 2\n> idea?\n\nBut why not\n\n\tsb->alloc = alloc_nr(sb->len + extra);\n\nHmm?\n\nCiao,\nDscho\n"},{"id":"49229","messageId":"Pine.LNX.4.64.0707311556150.14781@racer.site","threadId":"9314","inReplyTo":"1185891786.11086.40.camel@hinata.boston.redhat.com","subject":"Re: [PATCH 3/5] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-31T14:57:34Z","receivedAt":"2007-07-31T14:57:34Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 31 Jul 2007, Kristian H?gsberg wrote:\n\n> On Mon, 2007-07-30 at 21:36 -0700, Junio C Hamano wrote:\n> > Kristian Høgsberg <krh@redhat.com> writes:\n> > \n> > > +void strbuf_printf(struct strbuf *sb, const char *fmt, ...)\n> > > +{\n> > > +\tchar one_line[2048];\n> > > +\tva_list args;\n> > > +\tint len;\n> > \n> > Such a nice abstraction so far, and then at the highest level of\n> > callchain we have this hardcoded limit?\n> \n> Yeah, I know, it sucks.  I'd like to just run vsnprintf with a 0-sized\n> buffer to get the length, and then grow the buffer by that much, but\n> that's not very portable as far as I know.\n\nWe do have nfvasprintf()...\n\nCiao,\nDscho\n"},{"id":"49231","messageId":"1185895733.11086.54.camel@hinata.boston.redhat.com","threadId":"9314","inReplyTo":"Pine.LNX.4.64.0707311556150.14781@racer.site","subject":"Re: [PATCH 3/5] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-31T15:28:53Z","receivedAt":"2007-07-31T15:28:53Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Tue, 2007-07-31 at 15:57 +0100, Johannes Schindelin wrote:\n> Hi,\n> \n> On Tue, 31 Jul 2007, Kristian H?gsberg wrote:\n> \n> > On Mon, 2007-07-30 at 21:36 -0700, Junio C Hamano wrote:\n> > > Kristian Høgsberg <krh@redhat.com> writes:\n> > > \n> > > > +void strbuf_printf(struct strbuf *sb, const char *fmt, ...)\n> > > > +{\n> > > > +\tchar one_line[2048];\n> > > > +\tva_list args;\n> > > > +\tint len;\n> > > \n> > > Such a nice abstraction so far, and then at the highest level of\n> > > callchain we have this hardcoded limit?\n> > \n> > Yeah, I know, it sucks.  I'd like to just run vsnprintf with a 0-sized\n> > buffer to get the length, and then grow the buffer by that much, but\n> > that's not very portable as far as I know.\n> \n> We do have nfvasprintf()...\n\nAh, ok... it looks like it's using the second approach I described:\nprinting into a temp buffer, and realloc'ing and printing again if it\ndidn't fit.  But it dies with 'out of memory' if vsnprintf returns < 0,\nis that reasonable?  I'm not familiar with what will make vsnprintf\nreturn a negative value...  Also, that implementation potentially uses\nthe va_list twice, which isn't universally supported.  C99 introduces\nva_copy for this case, but that's also not available everywhere.\n\nHowever, if the nfvasprintf implementation in trace.c is fine, I'll just\nuse that approach in strbuf_printf too.  I'd just like to know that the\nabove issues aren't a problem on win32, since part of my motivation for\ndoing this is to make git available on windows so it will be easier for\npeople to choose git.\n\nKristian\n"},{"id":"49232","messageId":"1185896032.11086.57.camel@hinata.boston.redhat.com","threadId":"9314","inReplyTo":"Pine.LNX.4.64.0707311554220.14781@racer.site","subject":"Re: [PATCH 3/5] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-31T15:33:52Z","receivedAt":"2007-07-31T15:33:52Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"On Tue, 2007-07-31 at 15:55 +0100, Johannes Schindelin wrote:\n> Hi,\n> \n> On Tue, 31 Jul 2007, Kristian H?gsberg wrote:\n> \n> > On Mon, 2007-07-30 at 21:36 -0700, Junio C Hamano wrote:\n> > > Kristian Høgsberg <krh@redhat.com> writes:\n> > > \n> > > > +static void inline strbuf_grow(struct strbuf *sb, size_t extra)\n> > > > +{\n> > > > +\twhile (sb->alloc < sb->len + extra)\n> > > >  \t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n> > > > +\tsb->buf = xrealloc(sb->buf, sb->alloc);\n> > > > +}\n> > > \n> > > Somehow this while () loop to compute the growth factor bothers\n> > > me but that is probably a minor detail.\n> > \n> > Think of it as a more efficient way of adding one character at a time :)\n> > And it's logarithmic in the number of extra bytes.  By the way, I\n> > normally just double the size in these cases, which gives you amortized\n> > linear performance for adding to the buffer.  What's behind the * 3 / 2\n> > idea?\n> \n> But why not\n> \n> \tsb->alloc = alloc_nr(sb->len + extra);\n\nThat should work, or even ALLOC_GROW, I guess.  Didn't know about those\nmacros.  But still, why not just double the size?\n\nKristian\n"},{"id":"49241","messageId":"11859106503866-git-send-email-krh@redhat.com","threadId":"9314","inReplyTo":"7vodhtgq99.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] Add test case for basic commit functionality.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-31T19:37:30Z","receivedAt":"2007-07-31T19:37:30Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"Signed-off-by: Kristian Høgsberg <krh@redhat.com>\n---\n\nUpdate: using test_tick now, create test files as part of tests, split\n\tamend failure and bad options failure into separate test cases.\n\n t/t7501-commit.sh |  133 +++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 133 insertions(+), 0 deletions(-)\n create mode 100644 t/t7501-commit.sh\n\ndiff --git a/t/t7501-commit.sh b/t/t7501-commit.sh\nnew file mode 100644\nindex 0000000..ef0aab5\n--- /dev/null\n+++ b/t/t7501-commit.sh\n@@ -0,0 +1,133 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>\n+#\n+\n+# FIXME: Test the various index usages, -i and -o, test reflog,\n+# signoff, hooks\n+\n+test_description='git-commit'\n+. ./test-lib.sh\n+\n+test_tick\n+\n+test_expect_success \\\n+\t\"initial status\" \\\n+\t\"echo 'bongo bongo' >file &&\n+\t git-add file && \\\n+\t git-status | grep 'Initial commit'\"\n+\n+test_expect_failure \\\n+\t\"fail initial amend\" \\\n+\t\"git-commit --amend\"\n+\n+test_expect_success \\\n+\t\"initial commit\" \\\n+\t\"git-commit -m initial\"\n+\n+test_expect_failure \\\n+\t\"invalid options 1\" \\\n+\t\"git-commit --amend -F file\"\n+\n+test_expect_failure \\\n+\t\"invalid options 2\" \\\n+\t\"git-commit -C HEAD -m illegal\"\n+\n+test_expect_failure \\\n+\t\"using invalid commit with -C\" \\\n+\t\"git-commit -C bogus\"\n+\n+test_expect_failure \\\n+\t\"testing nothing to commit\" \\\n+\t\"git-commit -m initial\"\n+\n+test_expect_success \\\n+\t\"next commit\" \\\n+\t\"echo 'bongo bongo bongo' >file \\\n+\t git-commit -m next -a\"\n+\n+test_expect_failure \\\n+\t\"commit message from non-existing file\" \\\n+\t\"echo 'more bongo: bongo bongo bongo bongo' >file && \\\n+\t git-commit -F gah -a\"\n+\n+cat >msg <<EOF\n+\t\t\n+\n+  \n+Signed-off-by: hula\n+EOF\n+test_expect_failure \\\n+\t\"empty commit message\" \\\n+\t\"git-commit -F msg -a\"\n+\n+test_expect_success \\\n+\t\"commit message from file\" \\\n+\t\"echo 'this is the commit message, coming from a file' >msg && \\\n+\t git-commit -F msg -a\"\n+\n+cat >editor <<\\EOF\n+#!/bin/sh\n+sed -i -e \"s/a file/an amend commit/g\" $1\n+EOF\n+chmod 755 editor\n+\n+test_expect_success \\\n+\t\"amend commit\" \\\n+\t\"VISUAL=./editor git-commit --amend\"\n+\n+test_expect_failure \\\n+\t\"passing --amend and -F\" \\\n+\t\"echo 'enough with the bongos' >file && \\\n+\t git-commit -F msg --amend .\"\n+\n+test_expect_success \\\n+\t\"using message from other commit\" \\\n+\t\"git-commit -C HEAD^ .\"\n+\n+cat >editor <<\\EOF\n+#!/bin/sh\n+sed -i -e \"s/amend/older/g\" $1\n+EOF\n+chmod 755 editor\n+\n+test_expect_success \\\n+\t\"editing message from other commit\" \\\n+\t\"echo 'hula hula' >file && \\\n+\t VISUAL=./editor git-commit -c HEAD^ -a\"\n+\n+test_expect_success \\\n+\t\"message from stdin\" \\\n+\t\"echo 'silly new contents' >file && \\\n+\t echo commit message from stdin | git-commit -F - -a\"\n+\n+test_expect_success \\\n+\t\"overriding author from command line\" \\\n+\t\"echo 'gak' >file && \\\n+\t git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a\"\n+\n+test_expect_success \\\n+\t\"interactive add\" \\\n+\t\"echo 7 | git-commit --interactive | grep 'What now'\"\n+\n+test_expect_success \\\n+\t\"showing committed revisions\" \\\n+\t\"git-rev-list HEAD >current\"\n+\n+# We could just check the head sha1, but checking each commit makes it\n+# easier to isolate bugs.\n+\n+cat >expected <<\\EOF\n+72c0dc9855b0c9dadcbfd5a31cab072e0cb774ca\n+9b88fc14ce6b32e3d9ee021531a54f18a5cf38a2\n+3536bbb352c3a1ef9a420f5b4242d48578b92aa7\n+d381ac431806e53f3dd7ac2f1ae0534f36d738b9\n+4fd44095ad6334f3ef72e4c5ec8ddf108174b54a\n+402702b49136e7587daa9280e91e4bb7cb2179f7\n+EOF\n+\n+test_expect_success \\\n+    'validate git-rev-list output.' \\\n+    'diff current expected'\n+\n+test_done\n-- \n1.5.2.GIT\n"},{"id":"49245","messageId":"11859116632279-git-send-email-krh@redhat.com","threadId":"9314","inReplyTo":"7vhcnlgpeo.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Kristian Høgsberg","fromEmail":"krh@redhat.com","sentAt":"2007-07-31T19:54:23Z","receivedAt":"2007-07-31T19:54:23Z","isPatch":true,"sender":{"key":"krh@redhat.com","avatar":"https://gravatar.com/avatar/763dee6f9594ac474f725b137a39565792928e583ddf59b32befc2907409027e?d=mp&s=160"},"body":"Also, expose strbuf_add() and strbuf_add_char() to add raw data to the buffer.\n\nSigned-off-by: Kristian Høgsberg <krh@redhat.com>\n---\n\nOk, this gets uglier as we try to work around different versions of\nvsnprintf.  On windows, vsnprintf returns -1 if the output doesn't fit in\nthe given buffer.  What we do is to keep doubling the buffer size until it\nfits.  Not sure this is the best idea.\n\nThe old hardcoded limitation of just 2048 bytes wasn't too bad, considering\nthat it's just the limit for one strbuf_printf invocation, not the total\nsize of the strbuf contents.\n\nI dunno...\nKristian\n\n strbuf.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------\n strbuf.h |    3 ++\n 2 files changed, 65 insertions(+), 7 deletions(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex e33d06b..2805c11 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -11,16 +11,26 @@ static void strbuf_begin(struct strbuf *sb) {\n \tstrbuf_init(sb);\n }\n \n-static void inline strbuf_add(struct strbuf *sb, int ch) {\n-\tif (sb->alloc <= sb->len) {\n-\t\tsb->alloc = sb->alloc * 3 / 2 + 16;\n-\t\tsb->buf = xrealloc(sb->buf, sb->alloc);\n-\t}\n+static void inline strbuf_grow(struct strbuf *sb, size_t extra)\n+{\n+\tALLOC_GROW(sb->buf, sb->len + extra, sb->alloc);\n+}\n+\n+void strbuf_add(struct strbuf *sb, const char *data, size_t len)\n+{\n+\tstrbuf_grow(sb, len);\n+\tmemcpy(sb->buf + sb->len, data, len);\n+\tsb->len += len;\n+}\n+\n+void strbuf_add_char(struct strbuf *sb, int ch)\n+{\n+\tstrbuf_grow(sb, 1);\n \tsb->buf[sb->len++] = ch;\n }\n \n static void strbuf_end(struct strbuf *sb) {\n-\tstrbuf_add(sb, 0);\n+\tstrbuf_add_char(sb, 0);\n }\n \n void read_line(struct strbuf *sb, FILE *fp, int term) {\n@@ -33,9 +43,54 @@ void read_line(struct strbuf *sb, FILE *fp, int term) {\n \twhile ((ch = fgetc(fp)) != EOF) {\n \t\tif (ch == term)\n \t\t\tbreak;\n-\t\tstrbuf_add(sb, ch);\n+\t\tstrbuf_add_char(sb, ch);\n \t}\n \tif (ch == EOF && sb->len == 0)\n \t\tsb->eof = 1;\n \tstrbuf_end(sb);\n }\n+\n+void strbuf_printf(struct strbuf *sb, const char *fmt, ...)\n+{\n+\tchar buffer[2048];\n+\tva_list args;\n+\tint len, size = 2 * sizeof buffer;\n+\n+\tva_start(args, fmt);\n+\tlen = vsnprintf(buffer, sizeof(buffer), fmt, args);\n+\tva_end(args);\n+\n+\tif (len > sizeof(buffer)) {\n+\t\t/*\n+\t\t * Didn't fit in the buffer, but this vsnprintf at\n+\t\t * least gives us the required length back.  Grow the\n+\t\t * buffer acccordingly and try again.\n+\t\t */\n+\t\tstrbuf_grow(sb, len);\n+\t\tva_start(args, fmt);\n+\t\tlen = vsnprintf(sb->buf + sb->len,\n+\t\t\t\tsb->alloc - sb->len, fmt, args);\n+\t\tva_end(args);\n+\t} else if (len >= 0) {\n+\t\t/*\n+\t\t * The initial vsnprintf fit in the temp buffer, just\n+\t\t * copy it to the strbuf.\n+\t\t */\n+\t\tstrbuf_add(sb, buffer, len);\n+\t} else {\n+\t\t/*\n+\t\t * This vnsprintf sucks and just returns -1 when the\n+\t\t * buffer is too small.  Keep doubling the size until\n+\t\t * it fits.\n+\t\t */\n+\t\twhile (len < 0) {\n+\t\t\tstrbuf_grow(sb, size);\n+\t\t\tva_start(args, fmt);\n+\t\t\tlen = vsnprintf(sb->buf + sb->len,\n+\t\t\t\t\tsb->alloc - sb->len, fmt, args);\n+\t\t\tva_end(args);\n+\t\t\tsize *= 2;\n+\t\t}\n+\t}\n+}\n+\ndiff --git a/strbuf.h b/strbuf.h\nindex 74cc012..1e5d09e 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -9,5 +9,8 @@ struct strbuf {\n \n extern void strbuf_init(struct strbuf *);\n extern void read_line(struct strbuf *, FILE *, int);\n+extern void strbuf_add(struct strbuf *sb, const char *data, size_t len);\n+extern void strbuf_add_char(struct strbuf *sb, int ch);\n+extern void strbuf_printf(struct strbuf *sb, const char *fmt, ...);\n \n #endif /* STRBUF_H */\n-- \n1.5.2.GIT\n"},{"id":"49247","messageId":"7vhcnkfd1s.fsf@assigned-by-dhcp.cox.net","threadId":"9314","inReplyTo":"11859116632279-git-send-email-krh@redhat.com","subject":"Re: [PATCH] Add strbuf_printf() to do formatted printing to a strbuf.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-31T22:01:19Z","receivedAt":"2007-07-31T22:01:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Kristian Høgsberg <krh@redhat.com> writes:\n\n> The old hardcoded limitation of just 2048 bytes wasn't too bad, considering\n> that it's just the limit for one strbuf_printf invocation, not the total\n> size of the strbuf contents.\n\nI tend to agree with you now.  Sorry for the noise to make you\ngo to wild goose chase.  This does not look worth it.\n"}]}