summaryrefslogtreecommitdiff
path: root/strbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'strbuf.c')
-rw-r--r--strbuf.c172
1 files changed, 160 insertions, 12 deletions
diff --git a/strbuf.c b/strbuf.c
index f6a6cf78b9..bb0065ccaf 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -249,6 +249,42 @@ void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len)
strbuf_splice(sb, pos, 0, data, len);
}
+void strbuf_vinsertf(struct strbuf *sb, size_t pos, const char *fmt, va_list ap)
+{
+ int len, len2;
+ char save;
+ va_list cp;
+
+ if (pos > sb->len)
+ die("`pos' is too far after the end of the buffer");
+ va_copy(cp, ap);
+ len = vsnprintf(sb->buf + sb->len, 0, fmt, cp);
+ va_end(cp);
+ if (len < 0)
+ BUG("your vsnprintf is broken (returned %d)", len);
+ if (!len)
+ return; /* nothing to do */
+ if (unsigned_add_overflows(sb->len, len))
+ die("you want to use way too much memory");
+ strbuf_grow(sb, len);
+ memmove(sb->buf + pos + len, sb->buf + pos, sb->len - pos);
+ /* vsnprintf() will append a NUL, overwriting one of our characters */
+ save = sb->buf[pos + len];
+ len2 = vsnprintf(sb->buf + pos, len + 1, fmt, ap);
+ sb->buf[pos + len] = save;
+ if (len2 != len)
+ BUG("your vsnprintf is broken (returns inconsistent lengths)");
+ strbuf_setlen(sb, sb->len + len);
+}
+
+void strbuf_insertf(struct strbuf *sb, size_t pos, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ strbuf_vinsertf(sb, pos, fmt, ap);
+ va_end(ap);
+}
+
void strbuf_remove(struct strbuf *sb, size_t pos, size_t len)
{
strbuf_splice(sb, pos, len, "", 0);
@@ -268,6 +304,21 @@ void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
strbuf_setlen(sb, sb->len + sb2->len);
}
+const char *strbuf_join_argv(struct strbuf *buf,
+ int argc, const char **argv, char delim)
+{
+ if (!argc)
+ return buf->buf;
+
+ strbuf_addstr(buf, *argv);
+ while (--argc) {
+ strbuf_addch(buf, delim);
+ strbuf_addstr(buf, *(++argv));
+ }
+
+ return buf->buf;
+}
+
void strbuf_addchars(struct strbuf *sb, int c, size_t n)
{
strbuf_grow(sb, n);
@@ -380,6 +431,27 @@ void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn,
}
}
+size_t strbuf_expand_literal_cb(struct strbuf *sb,
+ const char *placeholder,
+ void *context)
+{
+ int ch;
+
+ switch (placeholder[0]) {
+ case 'n': /* newline */
+ strbuf_addch(sb, '\n');
+ return 1;
+ case 'x':
+ /* %x00 == NUL, %x0a == LF, etc. */
+ ch = hex2chr(placeholder + 1);
+ if (ch < 0)
+ return 0;
+ strbuf_addch(sb, ch);
+ return 3;
+ }
+ return 0;
+}
+
size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder,
void *context)
{
@@ -407,6 +479,21 @@ void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src)
}
}
+#define URL_UNSAFE_CHARS " <>\"%{}|\\^`:/?#[]@!$&'()*+,;="
+
+void strbuf_add_percentencode(struct strbuf *dst, const char *src)
+{
+ size_t i, len = strlen(src);
+
+ for (i = 0; i < len; i++) {
+ unsigned char ch = src[i];
+ if (ch <= 0x1F || ch >= 0x7F || strchr(URL_UNSAFE_CHARS, ch))
+ strbuf_addf(dst, "%%%02X", (unsigned char)ch);
+ else
+ strbuf_addch(dst, ch);
+ }
+}
+
size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
{
size_t res;
@@ -702,8 +789,10 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)
}
}
-static int is_rfc3986_reserved(char ch)
+int is_rfc3986_reserved_or_unreserved(char ch)
{
+ if (is_rfc3986_unreserved(ch))
+ return 1;
switch (ch) {
case '!': case '*': case '\'': case '(': case ')': case ';':
case ':': case '@': case '&': case '=': case '+': case '$':
@@ -713,20 +802,19 @@ static int is_rfc3986_reserved(char ch)
return 0;
}
-static int is_rfc3986_unreserved(char ch)
+int is_rfc3986_unreserved(char ch)
{
return isalnum(ch) ||
ch == '-' || ch == '_' || ch == '.' || ch == '~';
}
static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
- int reserved)
+ char_predicate allow_unencoded_fn)
{
strbuf_grow(sb, len);
while (len--) {
char ch = *s++;
- if (is_rfc3986_unreserved(ch) ||
- (!reserved && is_rfc3986_reserved(ch)))
+ if (allow_unencoded_fn(ch))
strbuf_addch(sb, ch);
else
strbuf_addf(sb, "%%%02x", (unsigned char)ch);
@@ -734,30 +822,62 @@ static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,
}
void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
- int reserved)
+ char_predicate allow_unencoded_fn)
{
- strbuf_add_urlencode(sb, s, strlen(s), reserved);
+ strbuf_add_urlencode(sb, s, strlen(s), allow_unencoded_fn);
}
-void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
+static void strbuf_humanise(struct strbuf *buf, off_t bytes,
+ int humanise_rate)
{
if (bytes > 1 << 30) {
- strbuf_addf(buf, "%u.%2.2u GiB",
+ strbuf_addf(buf,
+ humanise_rate == 0 ?
+ /* TRANSLATORS: IEC 80000-13:2008 gibibyte */
+ _("%u.%2.2u GiB") :
+ /* TRANSLATORS: IEC 80000-13:2008 gibibyte/second */
+ _("%u.%2.2u GiB/s"),
(unsigned)(bytes >> 30),
(unsigned)(bytes & ((1 << 30) - 1)) / 10737419);
} else if (bytes > 1 << 20) {
unsigned x = bytes + 5243; /* for rounding */
- strbuf_addf(buf, "%u.%2.2u MiB",
+ strbuf_addf(buf,
+ humanise_rate == 0 ?
+ /* TRANSLATORS: IEC 80000-13:2008 mebibyte */
+ _("%u.%2.2u MiB") :
+ /* TRANSLATORS: IEC 80000-13:2008 mebibyte/second */
+ _("%u.%2.2u MiB/s"),
x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
} else if (bytes > 1 << 10) {
unsigned x = bytes + 5; /* for rounding */
- strbuf_addf(buf, "%u.%2.2u KiB",
+ strbuf_addf(buf,
+ humanise_rate == 0 ?
+ /* TRANSLATORS: IEC 80000-13:2008 kibibyte */
+ _("%u.%2.2u KiB") :
+ /* TRANSLATORS: IEC 80000-13:2008 kibibyte/second */
+ _("%u.%2.2u KiB/s"),
x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
} else {
- strbuf_addf(buf, "%u bytes", (unsigned)bytes);
+ strbuf_addf(buf,
+ humanise_rate == 0 ?
+ /* TRANSLATORS: IEC 80000-13:2008 byte */
+ Q_("%u byte", "%u bytes", (unsigned)bytes) :
+ /* TRANSLATORS: IEC 80000-13:2008 byte/second */
+ Q_("%u byte/s", "%u bytes/s", (unsigned)bytes),
+ (unsigned)bytes);
}
}
+void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
+{
+ strbuf_humanise(buf, bytes, 0);
+}
+
+void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)
+{
+ strbuf_humanise(buf, bytes, 1);
+}
+
void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
{
if (!*path)
@@ -1020,3 +1140,31 @@ int strbuf_normalize_path(struct strbuf *src)
strbuf_release(&dst);
return 0;
}
+
+int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+ const char *const *env)
+{
+ char *path2 = NULL;
+ int fd, res = 0;
+
+ if (!is_absolute_path(path))
+ path = path2 = xstrdup(git_path("%s", path));
+
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0)
+ res = error_errno(_("could not open '%s' for writing"), path);
+ else if (write_in_full(fd, buffer->buf, buffer->len) < 0) {
+ res = error_errno(_("could not write to '%s'"), path);
+ close(fd);
+ } else if (close(fd) < 0)
+ res = error_errno(_("could not close '%s'"), path);
+ else {
+ strbuf_reset(buffer);
+ if (launch_editor(path, buffer, env) < 0)
+ res = error_errno(_("could not edit '%s'"), path);
+ unlink(path);
+ }
+
+ free(path2);
+ return res;
+}