Merge branch 'rs/strbuf-getwholeline-fix'
[git/git.git] / strbuf.c
index 977acba..323c49c 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -204,13 +204,6 @@ void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
        strbuf_setlen(sb, sb->len + sb2->len);
 }
 
-void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
-{
-       strbuf_grow(sb, len);
-       memcpy(sb->buf + sb->len, sb->buf + pos, len);
-       strbuf_setlen(sb, sb->len + len);
-}
-
 void strbuf_addchars(struct strbuf *sb, int c, size_t n)
 {
        strbuf_grow(sb, n);
@@ -449,6 +442,17 @@ int strbuf_getcwd(struct strbuf *sb)
                        strbuf_setlen(sb, strlen(sb->buf));
                        return 0;
                }
+
+               /*
+                * If getcwd(3) is implemented as a syscall that falls
+                * back to a regular lookup using readdir(3) etc. then
+                * we may be able to avoid EACCES by providing enough
+                * space to the syscall as it's not necessarily bound
+                * to the same restrictions as the fallback.
+                */
+               if (errno == EACCES && guessed_len < PATH_MAX)
+                       continue;
+
                if (errno != ERANGE)
                        break;
        }
@@ -775,14 +779,47 @@ char *xstrfmt(const char *fmt, ...)
        return ret;
 }
 
-void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm)
+void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,
+                    int tz_offset, int suppress_tz_name)
 {
+       struct strbuf munged_fmt = STRBUF_INIT;
        size_t hint = 128;
        size_t len;
 
        if (!*fmt)
                return;
 
+       /*
+        * There is no portable way to pass timezone information to
+        * strftime, so we handle %z and %Z here.
+        */
+       for (;;) {
+               const char *percent = strchrnul(fmt, '%');
+               strbuf_add(&munged_fmt, fmt, percent - fmt);
+               if (!*percent)
+                       break;
+               fmt = percent + 1;
+               switch (*fmt) {
+               case '%':
+                       strbuf_addstr(&munged_fmt, "%%");
+                       fmt++;
+                       break;
+               case 'z':
+                       strbuf_addf(&munged_fmt, "%+05d", tz_offset);
+                       fmt++;
+                       break;
+               case 'Z':
+                       if (suppress_tz_name) {
+                               fmt++;
+                               break;
+                       }
+                       /* FALLTHROUGH */
+               default:
+                       strbuf_addch(&munged_fmt, '%');
+               }
+       }
+       fmt = munged_fmt.buf;
+
        strbuf_grow(sb, hint);
        len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm);
 
@@ -794,17 +831,16 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm)
                 * 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);
+               strbuf_addch(&munged_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_release(&munged_fmt);
        strbuf_setlen(sb, sb->len + len);
 }