Merge branch 'tb/t0027-crlf'
[gitweb.git] / strbuf.c
index b4da9f5d05fc1f22f8910a21d8e352f2e5e9673f..107c45d29111a011a04daaa8fd0323ed9d973398 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -245,8 +245,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size
        static char prefix2[2];
 
        if (prefix1[0] != comment_line_char) {
-               sprintf(prefix1, "%c ", comment_line_char);
-               sprintf(prefix2, "%c", comment_line_char);
+               xsnprintf(prefix1, sizeof(prefix1), "%c ", comment_line_char);
+               xsnprintf(prefix2, sizeof(prefix2), "%c", comment_line_char);
        }
        add_lines(out, prefix1, prefix2, buf, size);
 }
@@ -364,19 +364,19 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint)
 
        strbuf_grow(sb, hint ? hint : 8192);
        for (;;) {
-               ssize_t cnt;
+               ssize_t want = sb->alloc - sb->len - 1;
+               ssize_t got = read_in_full(fd, sb->buf + sb->len, want);
 
-               cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1);
-               if (cnt < 0) {
+               if (got < 0) {
                        if (oldalloc == 0)
                                strbuf_release(sb);
                        else
                                strbuf_setlen(sb, oldlen);
                        return -1;
                }
-               if (!cnt)
+               sb->len += got;
+               if (got < want)
                        break;
-               sb->len += cnt;
                strbuf_grow(sb, 8192);
        }
 
@@ -435,6 +435,47 @@ int strbuf_getcwd(struct strbuf *sb)
        return -1;
 }
 
+#ifdef HAVE_GETDELIM
+int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
+{
+       ssize_t r;
+
+       if (feof(fp))
+               return EOF;
+
+       strbuf_reset(sb);
+
+       /* Translate slopbuf to NULL, as we cannot call realloc on it */
+       if (!sb->alloc)
+               sb->buf = NULL;
+       r = getdelim(&sb->buf, &sb->alloc, term, fp);
+
+       if (r > 0) {
+               sb->len = r;
+               return 0;
+       }
+       assert(r == -1);
+
+       /*
+        * Normally we would have called xrealloc, which will try to free
+        * memory and recover. But we have no way to tell getdelim() to do so.
+        * Worse, we cannot try to recover ENOMEM ourselves, because we have
+        * no idea how many bytes were read by getdelim.
+        *
+        * Dying here is reasonable. It mirrors what xrealloc would do on
+        * catastrophic memory failure. We skip the opportunity to free pack
+        * memory and retry, but that's unlikely to help for a malloc small
+        * enough to hold a single line of input, anyway.
+        */
+       if (errno == ENOMEM)
+               die("Out of memory, getdelim failed");
+
+       /* Restore slopbuf that we moved out of the way before */
+       if (!sb->buf)
+               strbuf_init(sb, 0);
+       return EOF;
+}
+#else
 int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
 {
        int ch;
@@ -443,18 +484,22 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
                return EOF;
 
        strbuf_reset(sb);
-       while ((ch = fgetc(fp)) != EOF) {
-               strbuf_grow(sb, 1);
+       flockfile(fp);
+       while ((ch = getc_unlocked(fp)) != EOF) {
+               if (!strbuf_avail(sb))
+                       strbuf_grow(sb, 1);
                sb->buf[sb->len++] = ch;
                if (ch == term)
                        break;
        }
+       funlockfile(fp);
        if (ch == EOF && sb->len == 0)
                return EOF;
 
        sb->buf[sb->len] = '\0';
        return 0;
 }
+#endif
 
 int strbuf_getline(struct strbuf *sb, FILE *fp, int term)
 {
@@ -665,3 +710,45 @@ char *xstrfmt(const char *fmt, ...)
 
        return ret;
 }
+
+void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm)
+{
+       size_t hint = 128;
+       size_t len;
+
+       if (!*fmt)
+               return;
+
+       strbuf_grow(sb, hint);
+       len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm);
+
+       if (!len) {
+               /*
+                * strftime reports "0" if it could not fit the result in the buffer.
+                * Unfortunately, it also reports "0" if the requested time string
+                * takes 0 bytes. So our strategy is to munge the format so that the
+                * output contains at least one character, and then drop the extra
+                * character before returning.
+                */
+               struct strbuf munged_fmt = STRBUF_INIT;
+               strbuf_addf(&munged_fmt, "%s ", fmt);
+               while (!len) {
+                       hint *= 2;
+                       strbuf_grow(sb, hint);
+                       len = strftime(sb->buf + sb->len, sb->alloc - sb->len,
+                                      munged_fmt.buf, tm);
+               }
+               strbuf_release(&munged_fmt);
+               len--; /* drop munged space */
+       }
+       strbuf_setlen(sb, sb->len + len);
+}
+
+void strbuf_add_unique_abbrev(struct strbuf *sb, const unsigned char *sha1,
+                             int abbrev_len)
+{
+       int r;
+       strbuf_grow(sb, GIT_SHA1_HEXSZ + 1);
+       r = find_unique_abbrev_r(sb->buf + sb->len, sha1, abbrev_len);
+       strbuf_setlen(sb, sb->len + r);
+}