Merge branch 'sg/completion-no-column' into maint
[gitweb.git] / strbuf.c
index c606f339d6d51a31e49870144c58297a656fede5..958387562184fe27c7e476ebb24d5547a55ae4ad 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -710,3 +710,102 @@ 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);
+}
+
+/*
+ * Returns the length of a line, without trailing spaces.
+ *
+ * If the line ends with newline, it will be removed too.
+ */
+static size_t cleanup(char *line, size_t len)
+{
+       while (len) {
+               unsigned char c = line[len - 1];
+               if (!isspace(c))
+                       break;
+               len--;
+       }
+
+       return len;
+}
+
+/*
+ * Remove empty lines from the beginning and end
+ * and also trailing spaces from every line.
+ *
+ * Turn multiple consecutive empty lines between paragraphs
+ * into just one empty line.
+ *
+ * If the input has only empty lines and spaces,
+ * no output will be produced.
+ *
+ * If last line does not have a newline at the end, one is added.
+ *
+ * Enable skip_comments to skip every line starting with comment
+ * character.
+ */
+void strbuf_stripspace(struct strbuf *sb, int skip_comments)
+{
+       int empties = 0;
+       size_t i, j, len, newlen;
+       char *eol;
+
+       /* We may have to add a newline. */
+       strbuf_grow(sb, 1);
+
+       for (i = j = 0; i < sb->len; i += len, j += newlen) {
+               eol = memchr(sb->buf + i, '\n', sb->len - i);
+               len = eol ? eol - (sb->buf + i) + 1 : sb->len - i;
+
+               if (skip_comments && len && sb->buf[i] == comment_line_char) {
+                       newlen = 0;
+                       continue;
+               }
+               newlen = cleanup(sb->buf + i, len);
+
+               /* Not just an empty line? */
+               if (newlen) {
+                       if (empties > 0 && j > 0)
+                               sb->buf[j++] = '\n';
+                       empties = 0;
+                       memmove(sb->buf + j, sb->buf + i, newlen);
+                       sb->buf[newlen + j++] = '\n';
+               } else {
+                       empties++;
+               }
+       }
+
+       strbuf_setlen(sb, j);
+}