Merge branch 'jk/write-file'
authorJunio C Hamano <gitster@pobox.com>
Tue, 19 Jul 2016 20:22:23 +0000 (13:22 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 19 Jul 2016 20:22:23 +0000 (13:22 -0700)
General code clean-up around a helper function to write a
single-liner to a file.

* jk/write-file:
branch: use write_file_buf instead of write_file
use write_file_buf where applicable
write_file: add format attribute
write_file: add pointer+len variant
write_file: use xopen
write_file: drop "gently" form
branch: use non-gentle write_file for branch description
am: ignore return value of write_file()
config: fix bogus fd check when setting up default config

1  2 
builtin/am.c
builtin/branch.c
builtin/merge.c
cache.h
wrapper.c
diff --combined builtin/am.c
index d5da5fe0900c6138337ee3f185884e454049eecd,5fdf5b4c2428b47db9dabf9a41094ec9a4db8964..3ac24482449bd6e048db85a5c04fdef3e00ab95b
@@@ -70,8 -70,7 +70,8 @@@ enum patch_format 
        PATCH_FORMAT_MBOX,
        PATCH_FORMAT_STGIT,
        PATCH_FORMAT_STGIT_SERIES,
 -      PATCH_FORMAT_HG
 +      PATCH_FORMAT_HG,
 +      PATCH_FORMAT_MBOXRD
  };
  
  enum keep_type {
@@@ -184,22 -183,22 +184,22 @@@ static inline const char *am_path(cons
  /**
   * For convenience to call write_file()
   */
- static int write_state_text(const struct am_state *state,
-                           const char *name, const char *string)
+ static void write_state_text(const struct am_state *state,
+                            const char *name, const char *string)
  {
-       return write_file(am_path(state, name), "%s", string);
+       write_file(am_path(state, name), "%s", string);
  }
  
- static int write_state_count(const struct am_state *state,
-                            const char *name, int value)
+ static void write_state_count(const struct am_state *state,
+                             const char *name, int value)
  {
-       return write_file(am_path(state, name), "%d", value);
+       write_file(am_path(state, name), "%d", value);
  }
  
- static int write_state_bool(const struct am_state *state,
-                           const char *name, int value)
+ static void write_state_bool(const struct am_state *state,
+                            const char *name, int value)
  {
-       return write_state_text(state, name, value ? "t" : "f");
+       write_state_text(state, name, value ? "t" : "f");
  }
  
  /**
@@@ -403,13 -402,8 +403,8 @@@ static int read_commit_msg(struct am_st
   */
  static void write_commit_msg(const struct am_state *state)
  {
-       int fd;
        const char *filename = am_path(state, "final-commit");
-       fd = xopen(filename, O_WRONLY | O_CREAT, 0666);
-       if (write_in_full(fd, state->msg, state->msg_len) < 0)
-               die_errno(_("could not write to %s"), filename);
-       close(fd);
+       write_file_buf(filename, state->msg, state->msg_len);
  }
  
  /**
@@@ -713,8 -707,7 +708,8 @@@ done
   * Splits out individual email patches from `paths`, where each path is either
   * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
   */
 -static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr)
 +static int split_mail_mbox(struct am_state *state, const char **paths,
 +                              int keep_cr, int mboxrd)
  {
        struct child_process cp = CHILD_PROCESS_INIT;
        struct strbuf last = STRBUF_INIT;
        argv_array_push(&cp.args, "-b");
        if (keep_cr)
                argv_array_push(&cp.args, "--keep-cr");
 +      if (mboxrd)
 +              argv_array_push(&cp.args, "--mboxrd");
        argv_array_push(&cp.args, "--");
        argv_array_pushv(&cp.args, paths);
  
@@@ -969,15 -960,13 +964,15 @@@ static int split_mail(struct am_state *
  
        switch (patch_format) {
        case PATCH_FORMAT_MBOX:
 -              return split_mail_mbox(state, paths, keep_cr);
 +              return split_mail_mbox(state, paths, keep_cr, 0);
        case PATCH_FORMAT_STGIT:
                return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
        case PATCH_FORMAT_STGIT_SERIES:
                return split_mail_stgit_series(state, paths, keep_cr);
        case PATCH_FORMAT_HG:
                return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
 +      case PATCH_FORMAT_MBOXRD:
 +              return split_mail_mbox(state, paths, keep_cr, 1);
        default:
                die("BUG: invalid patch_format");
        }
@@@ -2207,8 -2196,6 +2202,8 @@@ static int parse_opt_patchformat(const 
                *opt_value = PATCH_FORMAT_STGIT_SERIES;
        else if (!strcmp(arg, "hg"))
                *opt_value = PATCH_FORMAT_HG;
 +      else if (!strcmp(arg, "mboxrd"))
 +              *opt_value = PATCH_FORMAT_MBOXRD;
        else
                return error(_("Invalid value for --patch-format: %s"), arg);
        return 0;
diff --combined builtin/branch.c
index 12203fdcc8179a41ba43ee87eb8f906bc45380e3,1d41251a9a86a2533b550842b0c9500e61265492..bf0672578f3b1a875b7cc691a27f77e96f394909
@@@ -614,14 -614,11 +614,11 @@@ static int edit_branch_description(cons
        if (!buf.len || buf.buf[buf.len-1] != '\n')
                strbuf_addch(&buf, '\n');
        strbuf_commented_addf(&buf,
 -                  "Please edit the description for the branch\n"
 -                  "  %s\n"
 -                  "Lines starting with '%c' will be stripped.\n",
 +                  _("Please edit the description for the branch\n"
 +                    "  %s\n"
 +                    "Lines starting with '%c' will be stripped.\n"),
                    branch_name, comment_line_char);
-       if (write_file_gently(git_path(edit_description), "%s", buf.buf)) {
-               strbuf_release(&buf);
-               return error_errno(_("could not write branch description template"));
-       }
+       write_file_buf(git_path(edit_description), buf.buf, buf.len);
        strbuf_reset(&buf);
        if (launch_editor(git_path(edit_description), &buf, NULL)) {
                strbuf_release(&buf);
diff --combined builtin/merge.c
index 0dfe09eb1922750cdbf0d7cf3a4fd21b94a05cb5,2e782db7b46e406ef3ce5d00a82ef3947ff86e69..19b3bc2f2fafe08d5ec03ab493d9d8f189db275b
@@@ -211,7 -211,7 +211,7 @@@ static struct option builtin_merge_opti
                PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, FF_ONLY },
        OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
        OPT_BOOL(0, "verify-signatures", &verify_signatures,
 -              N_("Verify that the named commit has a valid GPG signature")),
 +              N_("verify that the named commit has a valid GPG signature")),
        OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
                N_("merge strategy to use"), option_parse_strategy),
        OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
@@@ -336,15 -336,9 +336,9 @@@ static void squash_message(struct commi
        struct rev_info rev;
        struct strbuf out = STRBUF_INIT;
        struct commit_list *j;
-       const char *filename;
-       int fd;
        struct pretty_print_context ctx = {0};
  
        printf(_("Squash commit -- not updating HEAD\n"));
-       filename = git_path_squash_msg();
-       fd = open(filename, O_WRONLY | O_CREAT, 0666);
-       if (fd < 0)
-               die_errno(_("Could not write to '%s'"), filename);
  
        init_revisions(&rev, NULL);
        rev.ignore_merges = 1;
                        oid_to_hex(&commit->object.oid));
                pretty_print_commit(&ctx, commit, &out);
        }
-       if (write_in_full(fd, out.buf, out.len) != out.len)
-               die_errno(_("Writing SQUASH_MSG"));
-       if (close(fd))
-               die_errno(_("Finishing SQUASH_MSG"));
+       write_file_buf(git_path_squash_msg(), out.buf, out.len);
        strbuf_release(&out);
  }
  
@@@ -501,7 -492,7 +492,7 @@@ static void merge_name(const char *remo
                if (ref_exists(truname.buf)) {
                        strbuf_addf(msg,
                                    "%s\t\tbranch '%s'%s of .\n",
 -                                  sha1_to_hex(remote_head->object.oid.hash),
 +                                  oid_to_hex(&remote_head->object.oid),
                                    truname.buf + 11,
                                    (early ? " (early part)" : ""));
                        strbuf_release(&truname);
                desc = merge_remote_util(remote_head);
                if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
                        strbuf_addf(msg, "%s\t\t%s '%s'\n",
 -                                  sha1_to_hex(desc->obj->oid.hash),
 +                                  oid_to_hex(&desc->obj->oid),
                                    typename(desc->obj->type),
                                    remote);
                        goto cleanup;
        }
  
        strbuf_addf(msg, "%s\t\tcommit '%s'\n",
 -              sha1_to_hex(remote_head->object.oid.hash), remote);
 +              oid_to_hex(&remote_head->object.oid), remote);
  cleanup:
        strbuf_release(&buf);
        strbuf_release(&bname);
@@@ -756,18 -747,6 +747,6 @@@ static void add_strategies(const char *
  
  }
  
- static void write_merge_msg(struct strbuf *msg)
- {
-       const char *filename = git_path_merge_msg();
-       int fd = open(filename, O_WRONLY | O_CREAT, 0666);
-       if (fd < 0)
-               die_errno(_("Could not open '%s' for writing"),
-                         filename);
-       if (write_in_full(fd, msg->buf, msg->len) != msg->len)
-               die_errno(_("Could not write to '%s'"), filename);
-       close(fd);
- }
  static void read_merge_msg(struct strbuf *msg)
  {
        const char *filename = git_path_merge_msg();
@@@ -801,7 -780,7 +780,7 @@@ static void prepare_to_commit(struct co
        strbuf_addch(&msg, '\n');
        if (0 < option_edit)
                strbuf_commented_addf(&msg, _(merge_editor_comment), comment_line_char);
-       write_merge_msg(&msg);
+       write_file_buf(git_path_merge_msg(), msg.buf, msg.len);
        if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg",
                            git_path_merge_msg(), "merge", NULL))
                abort_commit(remoteheads, NULL);
@@@ -964,8 -943,6 +943,6 @@@ static int setup_with_upstream(const ch
  
  static void write_merge_state(struct commit_list *remoteheads)
  {
-       const char *filename;
-       int fd;
        struct commit_list *j;
        struct strbuf buf = STRBUF_INIT;
  
                }
                strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
        }
-       filename = git_path_merge_head();
-       fd = open(filename, O_WRONLY | O_CREAT, 0666);
-       if (fd < 0)
-               die_errno(_("Could not open '%s' for writing"), filename);
-       if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-               die_errno(_("Could not write to '%s'"), filename);
-       close(fd);
+       write_file_buf(git_path_merge_head(), buf.buf, buf.len);
        strbuf_addch(&merge_msg, '\n');
-       write_merge_msg(&merge_msg);
+       write_file_buf(git_path_merge_msg(), merge_msg.buf, merge_msg.len);
  
-       filename = git_path_merge_mode();
-       fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
-       if (fd < 0)
-               die_errno(_("Could not open '%s' for writing"), filename);
        strbuf_reset(&buf);
        if (fast_forward == FF_NO)
                strbuf_addf(&buf, "no-ff");
-       if (write_in_full(fd, buf.buf, buf.len) != buf.len)
-               die_errno(_("Could not write to '%s'"), filename);
-       close(fd);
+       write_file_buf(git_path_merge_mode(), buf.buf, buf.len);
  }
  
  static int default_edit_option(void)
        if (e) {
                int v = git_config_maybe_bool(name, e);
                if (v < 0)
 -                      die("Bad value '%s' in environment '%s'", e, name);
 +                      die(_("Bad value '%s' in environment '%s'"), e, name);
                return v;
        }
  
@@@ -1115,7 -1080,7 +1080,7 @@@ static void handle_fetch_head(struct co
                if (!commit) {
                        if (ptr)
                                *ptr = '\0';
 -                      die("not something we can merge in %s: %s",
 +                      die(_("not something we can merge in %s: %s"),
                            filename, merge_names->buf + pos);
                }
                remotes = &commit_list_insert(commit, remotes)->next;
@@@ -1149,7 -1114,7 +1114,7 @@@ static struct commit_list *collect_pare
                        struct commit *commit = get_merge_parent(argv[i]);
                        if (!commit)
                                help_unknown_ref(argv[i], "merge",
 -                                               "not something we can merge");
 +                                               _("not something we can merge"));
                        remotes = &commit_list_insert(commit, remotes)->next;
                }
                remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
@@@ -1366,7 -1331,7 +1331,7 @@@ int cmd_merge(int argc, const char **ar
        for (p = remoteheads; p; p = p->next) {
                struct commit *commit = p->item;
                strbuf_addf(&buf, "GITHEAD_%s",
 -                          sha1_to_hex(commit->object.oid.hash));
 +                          oid_to_hex(&commit->object.oid));
                setenv(buf.buf, merge_remote_util(commit)->name, 1);
                strbuf_reset(&buf);
                if (fast_forward != FF_ONLY &&
                 * If head can reach all the merge then we are up to date.
                 * but first the most common case of merging one remote.
                 */
 -              finish_up_to_date("Already up-to-date.");
 +              finish_up_to_date(_("Already up-to-date."));
                goto done;
        } else if (fast_forward != FF_NO && !remoteheads->next &&
                        !common->next &&
 -                      !hashcmp(common->item->object.oid.hash, head_commit->object.oid.hash)) {
 +                      !oidcmp(&common->item->object.oid, &head_commit->object.oid)) {
                /* Again the most common case of merging one remote. */
                struct strbuf msg = STRBUF_INIT;
                struct commit *commit;
                         * HEAD^^" would be missed.
                         */
                        common_one = get_merge_bases(head_commit, j->item);
 -                      if (hashcmp(common_one->item->object.oid.hash,
 -                              j->item->object.oid.hash)) {
 +                      if (oidcmp(&common_one->item->object.oid, &j->item->object.oid)) {
                                up_to_date = 0;
                                break;
                        }
                }
                if (up_to_date) {
 -                      finish_up_to_date("Already up-to-date. Yeeah!");
 +                      finish_up_to_date(_("Already up-to-date. Yeeah!"));
                        goto done;
                }
        }
             * Stash away the local changes so that we can try more than one.
             */
            save_state(stash))
 -              hashcpy(stash, null_sha1);
 +              hashclr(stash);
  
        for (i = 0; i < use_strategies_nr; i++) {
                int ret;
diff --combined cache.h
index a93d1b7f5ddd504afa9d9de8988038e165bf6056,b2d24da73f6b20e409a467141545b3d17acdbbe8..2bf97cc55f1170d25549b76144993acea1a807b5
+++ b/cache.h
@@@ -367,8 -367,8 +367,8 @@@ extern void free_name_hash(struct index
  #define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name))
  #define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
  #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
 -#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
 -#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
 +#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags), 0)
 +#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags), 0)
  #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
  #define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
  #define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
@@@ -581,8 -581,8 +581,8 @@@ extern int remove_file_from_index(struc
  #define ADD_CACHE_IGNORE_ERRORS       4
  #define ADD_CACHE_IGNORE_REMOVAL 8
  #define ADD_CACHE_INTENT 16
 -extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
 -extern int add_file_to_index(struct index_state *, const char *path, int flags);
 +extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags, int force_mode);
 +extern int add_file_to_index(struct index_state *, const char *path, int flags, int force_mode);
  extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
  extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
  extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
@@@ -1193,7 -1193,6 +1193,7 @@@ extern int get_oid_hex(const char *hex
   *   printf("%s -> %s", sha1_to_hex(one), sha1_to_hex(two));
   */
  extern char *sha1_to_hex_r(char *out, const unsigned char *sha1);
 +extern char *oid_to_hex_r(char *out, const struct object_id *oid);
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
  extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
  
@@@ -1605,16 -1604,6 +1605,16 @@@ extern const char *get_log_output_encod
  extern const char *get_commit_output_encoding(void);
  
  extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 +
 +enum config_scope {
 +      CONFIG_SCOPE_UNKNOWN = 0,
 +      CONFIG_SCOPE_SYSTEM,
 +      CONFIG_SCOPE_GLOBAL,
 +      CONFIG_SCOPE_REPO,
 +      CONFIG_SCOPE_CMDLINE,
 +};
 +
 +extern enum config_scope current_config_scope(void);
  extern const char *current_config_origin_type(void);
  extern const char *current_config_name(void);
  
@@@ -1707,8 -1696,6 +1707,8 @@@ extern int ignore_untracked_cache_confi
  struct key_value_info {
        const char *filename;
        int linenr;
 +      const char *origin_type;
 +      enum config_scope scope;
  };
  
  extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
@@@ -1734,6 -1721,7 +1734,6 @@@ extern int copy_file(const char *dst, c
  extern int copy_file_with_time(const char *dst, const char *src, int mode);
  
  extern void write_or_die(int fd, const void *buf, size_t count);
 -extern int write_or_whine(int fd, const void *buf, size_t count, const char *msg);
  extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char *msg);
  extern void fsync_or_die(int fd, const char *);
  
@@@ -1746,8 -1734,21 +1746,21 @@@ static inline ssize_t write_str_in_full
        return write_in_full(fd, str, strlen(str));
  }
  
- extern int write_file(const char *path, const char *fmt, ...);
- extern int write_file_gently(const char *path, const char *fmt, ...);
+ /**
+  * Open (and truncate) the file at path, write the contents of buf to it,
+  * and close it. Dies if any errors are encountered.
+  */
+ extern void write_file_buf(const char *path, const char *buf, size_t len);
+ /**
+  * Like write_file_buf(), but format the contents into a buffer first.
+  * Additionally, write_file() will append a newline if one is not already
+  * present, making it convenient to write text files:
+  *
+  *   write_file(path, "counter: %d", ctr);
+  */
+ __attribute__((format (printf, 2, 3)))
+ extern void write_file(const char *path, const char *fmt, ...);
  
  /* pager.c */
  extern void setup_pager(void);
@@@ -1784,7 -1785,7 +1797,7 @@@ void packet_trace_identity(const char *
   * return 0 if success, 1 - if addition of a file failed and
   * ADD_FILES_IGNORE_ERRORS was specified in flags
   */
 -int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
 +int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags, int force_mode);
  
  /* diff.c */
  extern int diff_auto_refresh_index;
diff --combined wrapper.c
index 26db215f0c2f38e426d76e41fb16b7cb8deadeb3,b827206a42fb8c133c9931f4f5a56174d71c5ad6..e7f197996868a614c84537ad96fc672ea901148d
+++ b/wrapper.c
@@@ -227,24 -227,6 +227,24 @@@ int xopen(const char *path, int oflag, 
        }
  }
  
 +static int handle_nonblock(int fd, short poll_events, int err)
 +{
 +      struct pollfd pfd;
 +
 +      if (err != EAGAIN && err != EWOULDBLOCK)
 +              return 0;
 +
 +      pfd.fd = fd;
 +      pfd.events = poll_events;
 +
 +      /*
 +       * no need to check for errors, here;
 +       * a subsequent read/write will detect unrecoverable errors
 +       */
 +      poll(&pfd, 1, -1);
 +      return 1;
 +}
 +
  /*
   * xread() is the same a read(), but it automatically restarts read()
   * operations with a recoverable error (EAGAIN and EINTR). xread()
@@@ -260,8 -242,20 +260,8 @@@ ssize_t xread(int fd, void *buf, size_
                if (nr < 0) {
                        if (errno == EINTR)
                                continue;
 -                      if (errno == EAGAIN || errno == EWOULDBLOCK) {
 -                              struct pollfd pfd;
 -                              pfd.events = POLLIN;
 -                              pfd.fd = fd;
 -                              /*
 -                               * it is OK if this poll() failed; we
 -                               * want to leave this infinite loop
 -                               * only when read() returns with
 -                               * success, or an expected failure,
 -                               * which would be checked by the next
 -                               * call to read(2).
 -                               */
 -                              poll(&pfd, 1, -1);
 -                      }
 +                      if (handle_nonblock(fd, POLLIN, errno))
 +                              continue;
                }
                return nr;
        }
@@@ -279,13 -273,8 +279,13 @@@ ssize_t xwrite(int fd, const void *buf
            len = MAX_IO_SIZE;
        while (1) {
                nr = write(fd, buf, len);
 -              if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
 -                      continue;
 +              if (nr < 0) {
 +                      if (errno == EINTR)
 +                              continue;
 +                      if (handle_nonblock(fd, POLLOUT, errno))
 +                              continue;
 +              }
 +
                return nr;
        }
  }
@@@ -651,56 -640,28 +651,28 @@@ int xsnprintf(char *dst, size_t max, co
        return len;
  }
  
- static int write_file_v(const char *path, int fatal,
-                       const char *fmt, va_list params)
+ void write_file_buf(const char *path, const char *buf, size_t len)
  {
-       struct strbuf sb = STRBUF_INIT;
-       int fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0666);
-       if (fd < 0) {
-               if (fatal)
-                       die_errno(_("could not open %s for writing"), path);
-               return -1;
-       }
-       strbuf_vaddf(&sb, fmt, params);
-       strbuf_complete_line(&sb);
-       if (write_in_full(fd, sb.buf, sb.len) != sb.len) {
-               int err = errno;
-               close(fd);
-               strbuf_release(&sb);
-               errno = err;
-               if (fatal)
-                       die_errno(_("could not write to %s"), path);
-               return -1;
-       }
-       strbuf_release(&sb);
-       if (close(fd)) {
-               if (fatal)
-                       die_errno(_("could not close %s"), path);
-               return -1;
-       }
-       return 0;
+       int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+       if (write_in_full(fd, buf, len) != len)
+               die_errno(_("could not write to %s"), path);
+       if (close(fd))
+               die_errno(_("could not close %s"), path);
  }
  
int write_file(const char *path, const char *fmt, ...)
void write_file(const char *path, const char *fmt, ...)
  {
-       int status;
        va_list params;
+       struct strbuf sb = STRBUF_INIT;
  
        va_start(params, fmt);
-       status = write_file_v(path, 1, fmt, params);
+       strbuf_vaddf(&sb, fmt, params);
        va_end(params);
-       return status;
- }
  
- int write_file_gently(const char *path, const char *fmt, ...)
- {
-       int status;
-       va_list params;
+       strbuf_complete_line(&sb);
  
-       va_start(params, fmt);
-       status = write_file_v(path, 0, fmt, params);
-       va_end(params);
-       return status;
+       write_file_buf(path, sb.buf, sb.len);
+       strbuf_release(&sb);
  }
  
  void sleep_millisec(int millisec)