strbuf: let strbuf_addftime handle %z and %Z itself
There is no portable way to pass timezone information to strftime. Add parameters for timezone offset and name to strbuf_addftime and let it handle the timezone-related format specifiers %z and %Z internally. Callers can opt out for %Z by passing NULL as timezone name. %z is always handled internally -- this helps on Windows, where strftime would expand it to a timezone name (same as %Z), in violation of POSIX. Modifiers are not handled, e.g. %Ez is still passed to strftime. Use an empty string as timezone name in show_date (the only current caller) for now because we only have the timezone offset in non-local mode. POSIX allows %Z to resolve to an empty string in case of missing information. Helped-by: Ulrich Mueller <ulm@gentoo.org> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
b06d364310
commit
c3fbf81a85
41
strbuf.c
41
strbuf.c
@ -785,14 +785,48 @@ 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, const char *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 (tz_name) {
|
||||
strbuf_addstr(&munged_fmt, 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);
|
||||
|
||||
@ -804,17 +838,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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user