diff options
Diffstat (limited to 'strbuf.c')
-rw-r--r-- | strbuf.c | 202 |
1 files changed, 175 insertions, 27 deletions
@@ -1,5 +1,6 @@ #include "cache.h" #include "refs.h" +#include "string-list.h" #include "utf8.h" int starts_with(const char *str, const char *prefix) @@ -11,6 +12,37 @@ int starts_with(const char *str, const char *prefix) return 0; } +int istarts_with(const char *str, const char *prefix) +{ + for (; ; str++, prefix++) + if (!*prefix) + return 1; + else if (tolower(*str) != tolower(*prefix)) + return 0; +} + +int skip_to_optional_arg_default(const char *str, const char *prefix, + const char **arg, const char *def) +{ + const char *p; + + if (!skip_prefix(str, prefix, &p)) + return 0; + + if (!*p) { + if (arg) + *arg = def; + return 1; + } + + if (*p != '=') + return 0; + + if (arg) + *arg = p + 1; + return 1; +} + /* * Used as the default ->buf value, so that people can always assume * buf is non NULL and ->buf is NUL terminated even for a freshly @@ -73,6 +105,7 @@ void strbuf_trim(struct strbuf *sb) strbuf_rtrim(sb); strbuf_ltrim(sb); } + void strbuf_rtrim(struct strbuf *sb) { while (sb->len > 0 && isspace((unsigned char)sb->buf[sb->len - 1])) @@ -80,6 +113,13 @@ void strbuf_rtrim(struct strbuf *sb) sb->buf[sb->len] = '\0'; } +void strbuf_trim_trailing_dir_sep(struct strbuf *sb) +{ + while (sb->len > 0 && is_dir_sep((unsigned char)sb->buf[sb->len - 1])) + sb->len--; + sb->buf[sb->len] = '\0'; +} + void strbuf_ltrim(struct strbuf *sb) { char *b = sb->buf; @@ -94,7 +134,7 @@ void strbuf_ltrim(struct strbuf *sb) int strbuf_reencode(struct strbuf *sb, const char *from, const char *to) { char *out; - int len; + size_t len; if (same_encoding(from, to)) return 0; @@ -141,6 +181,21 @@ struct strbuf **strbuf_split_buf(const char *str, size_t slen, return ret; } +void strbuf_add_separated_string_list(struct strbuf *str, + const char *sep, + struct string_list *slist) +{ + struct string_list_item *item; + int sep_needed = 0; + + for_each_string_list_item(item, slist) { + if (sep_needed) + strbuf_addstr(str, sep); + strbuf_addstr(str, item->string); + sep_needed = 1; + } +} + void strbuf_list_free(struct strbuf **sbs) { struct strbuf **s = sbs; @@ -154,7 +209,7 @@ void strbuf_list_free(struct strbuf **sbs) int strbuf_cmp(const struct strbuf *a, const struct strbuf *b) { - int len = a->len < b->len ? a->len: b->len; + size_t len = a->len < b->len ? a->len: b->len; int cmp = memcmp(a->buf, b->buf, len); if (cmp) return cmp; @@ -187,7 +242,7 @@ void strbuf_insert(struct strbuf *sb, size_t pos, const void *data, size_t len) void strbuf_remove(struct strbuf *sb, size_t pos, size_t len) { - strbuf_splice(sb, pos, len, NULL, 0); + strbuf_splice(sb, pos, len, "", 0); } void strbuf_add(struct strbuf *sb, const void *data, size_t len) @@ -197,11 +252,11 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len) strbuf_setlen(sb, sb->len + len); } -void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len) +void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) { - strbuf_grow(sb, len); - memcpy(sb->buf + sb->len, sb->buf + pos, len); - strbuf_setlen(sb, sb->len + len); + strbuf_grow(sb, sb2->len); + memcpy(sb->buf + sb->len, sb2->buf, sb2->len); + strbuf_setlen(sb, sb->len + sb2->len); } void strbuf_addchars(struct strbuf *sb, int c, size_t n) @@ -279,12 +334,12 @@ void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap) len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp); va_end(cp); if (len < 0) - die("BUG: your vsnprintf is broken (returned %d)", len); + BUG("your vsnprintf is broken (returned %d)", len); if (len > strbuf_avail(sb)) { strbuf_grow(sb, len); len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); if (len > strbuf_avail(sb)) - die("BUG: your vsnprintf is broken (insatiable)"); + BUG("your vsnprintf is broken (insatiable)"); } strbuf_setlen(sb, sb->len + len); } @@ -334,7 +389,7 @@ size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src) { - int i, len = src->len; + size_t i, len = src->len; for (i = 0; i < len; i++) { if (src->buf[i] == '%') @@ -386,12 +441,15 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, size_t hint) ssize_t strbuf_read_once(struct strbuf *sb, int fd, size_t hint) { + size_t oldalloc = sb->alloc; ssize_t cnt; strbuf_grow(sb, hint ? hint : 8192); cnt = xread(fd, sb->buf + sb->len, sb->alloc - sb->len - 1); if (cnt > 0) strbuf_setlen(sb, sb->len + cnt); + else if (oldalloc == 0) + strbuf_release(sb); return cnt; } @@ -411,7 +469,7 @@ int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint) hint = 32; while (hint < STRBUF_MAXLINK) { - int len; + ssize_t len; strbuf_grow(sb, hint); len = readlink(path, sb->buf, hint); @@ -442,6 +500,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; } @@ -465,6 +534,7 @@ int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term) /* Translate slopbuf to NULL, as we cannot call realloc on it */ if (!sb->alloc) sb->buf = NULL; + errno = 0; r = getdelim(&sb->buf, &sb->alloc, term, fp); if (r > 0) { @@ -575,14 +645,18 @@ ssize_t strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) { int fd; ssize_t len; + int saved_errno; fd = open(path, O_RDONLY); if (fd < 0) return -1; len = strbuf_read(sb, fd, hint); + saved_errno = errno; close(fd); - if (len < 0) + if (len < 0) { + errno = saved_errno; return -1; + } return len; } @@ -646,7 +720,7 @@ static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len, (!reserved && is_rfc3986_reserved(ch))) strbuf_addch(sb, ch); else - strbuf_addf(sb, "%%%02x", ch); + strbuf_addf(sb, "%%%02x", (unsigned char)ch); } } @@ -660,18 +734,18 @@ void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes) { if (bytes > 1 << 30) { strbuf_addf(buf, "%u.%2.2u GiB", - (int)(bytes >> 30), - (int)(bytes & ((1 << 30) - 1)) / 10737419); + (unsigned)(bytes >> 30), + (unsigned)(bytes & ((1 << 30) - 1)) / 10737419); } else if (bytes > 1 << 20) { - int x = bytes + 5243; /* for rounding */ + unsigned x = bytes + 5243; /* for rounding */ strbuf_addf(buf, "%u.%2.2u MiB", x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20); } else if (bytes > 1 << 10) { - int x = bytes + 5; /* for rounding */ + unsigned x = bytes + 5; /* for rounding */ strbuf_addf(buf, "%u.%2.2u KiB", x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10); } else { - strbuf_addf(buf, "%u bytes", (int)bytes); + strbuf_addf(buf, "%u bytes", (unsigned)bytes); } } @@ -700,6 +774,17 @@ void strbuf_add_absolute_path(struct strbuf *sb, const char *path) strbuf_addstr(sb, path); } +void strbuf_add_real_path(struct strbuf *sb, const char *path) +{ + if (sb->len) { + struct strbuf resolved = STRBUF_INIT; + strbuf_realpath(&resolved, path, 1); + strbuf_addbuf(sb, &resolved); + strbuf_release(&resolved); + } else + strbuf_realpath(sb, path, 1); +} + int printf_ln(const char *fmt, ...) { int ret; @@ -733,7 +818,18 @@ char *xstrdup_tolower(const char *string) result = xmallocz(len); for (i = 0; i < len; i++) result[i] = tolower(string[i]); - result[i] = '\0'; + return result; +} + +char *xstrdup_toupper(const char *string) +{ + char *result; + size_t len, i; + + len = strlen(string); + result = xmallocz(len); + for (i = 0; i < len; i++) + result[i] = toupper(string[i]); return result; } @@ -756,14 +852,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); @@ -775,26 +904,25 @@ 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); } -void strbuf_add_unique_abbrev(struct strbuf *sb, const unsigned char *sha1, +void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid, 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_grow(sb, GIT_MAX_HEXSZ + 1); + r = find_unique_abbrev_r(sb->buf + sb->len, oid, abbrev_len); strbuf_setlen(sb, sb->len + r); } @@ -832,7 +960,7 @@ static size_t cleanup(char *line, size_t len) */ void strbuf_stripspace(struct strbuf *sb, int skip_comments) { - int empties = 0; + size_t empties = 0; size_t i, j, len, newlen; char *eol; @@ -863,3 +991,23 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments) strbuf_setlen(sb, j); } + +int strbuf_normalize_path(struct strbuf *src) +{ + struct strbuf dst = STRBUF_INIT; + + strbuf_grow(&dst, src->len); + if (normalize_path_copy(dst.buf, src->buf) < 0) { + strbuf_release(&dst); + return -1; + } + + /* + * normalize_path does not tell us the new length, so we have to + * compute it by looking for the new NUL it placed + */ + strbuf_setlen(&dst, strlen(dst.buf)); + strbuf_swap(src, &dst); + strbuf_release(&dst); + return 0; +} |