for-each-ref: clean up code
[gitweb.git] / strbuf.c
index a4486a9e499d74bda3b3db10ef42d4975f7f7cbf..0d4f4e54ec1ff1f0d37155e8049476d802a7c7e5 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -204,6 +204,13 @@ void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
        strbuf_setlen(sb, sb->len + len);
 }
 
+void strbuf_addchars(struct strbuf *sb, int c, size_t n)
+{
+       strbuf_grow(sb, n);
+       memset(sb->buf + sb->len, c, n);
+       strbuf_setlen(sb, sb->len + n);
+}
+
 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 {
        va_list ap;
@@ -407,6 +414,68 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint)
        return -1;
 }
 
+int strbuf_getcwd(struct strbuf *sb)
+{
+       size_t oldalloc = sb->alloc;
+       size_t guessed_len = 128;
+
+       for (;; guessed_len *= 2) {
+               strbuf_grow(sb, guessed_len);
+               if (getcwd(sb->buf, sb->alloc)) {
+                       strbuf_setlen(sb, strlen(sb->buf));
+                       return 0;
+               }
+               if (errno != ERANGE)
+                       break;
+       }
+       if (oldalloc == 0)
+               strbuf_release(sb);
+       else
+               strbuf_reset(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;
@@ -415,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)
 {
@@ -556,6 +629,31 @@ void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
        }
 }
 
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
+{
+       if (!*path)
+               die("The empty string is not a valid path");
+       if (!is_absolute_path(path)) {
+               struct stat cwd_stat, pwd_stat;
+               size_t orig_len = sb->len;
+               char *cwd = xgetcwd();
+               char *pwd = getenv("PWD");
+               if (pwd && strcmp(pwd, cwd) &&
+                   !stat(cwd, &cwd_stat) &&
+                   (cwd_stat.st_dev || cwd_stat.st_ino) &&
+                   !stat(pwd, &pwd_stat) &&
+                   pwd_stat.st_dev == cwd_stat.st_dev &&
+                   pwd_stat.st_ino == cwd_stat.st_ino)
+                       strbuf_addstr(sb, pwd);
+               else
+                       strbuf_addstr(sb, cwd);
+               if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
+                       strbuf_addch(sb, '/');
+               free(cwd);
+       }
+       strbuf_addstr(sb, path);
+}
+
 int printf_ln(const char *fmt, ...)
 {
        int ret;