| 1001 | } |
| 1002 | |
| 1003 | void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm, |
| 1004 | int tz_offset, int suppress_tz_name) |
| 1005 | { |
| 1006 | struct strbuf munged_fmt = STRBUF_INIT; |
| 1007 | size_t hint = 128; |
| 1008 | size_t len; |
| 1009 | |
| 1010 | if (!*fmt) |
| 1011 | return; |
| 1012 | |
| 1013 | /* |
| 1014 | * There is no portable way to pass timezone information to |
| 1015 | * strftime, so we handle %z and %Z here. Likewise '%s', because |
| 1016 | * going back to an epoch time requires knowing the zone. |
| 1017 | * |
| 1018 | * Note that tz_offset is in the "[-+]HHMM" decimal form; this is what |
| 1019 | * we want for %z, but the computation for %s has to convert to number |
| 1020 | * of seconds. |
| 1021 | */ |
| 1022 | while (strbuf_expand_step(&munged_fmt, &fmt)) { |
| 1023 | if (skip_prefix(fmt, "%", &fmt)) |
| 1024 | strbuf_addstr(&munged_fmt, "%%"); |
| 1025 | else if (skip_prefix(fmt, "s", &fmt)) |
| 1026 | strbuf_addf(&munged_fmt, "%"PRItime, |
| 1027 | (timestamp_t)tm_to_time_t(tm) - |
| 1028 | 3600 * (tz_offset / 100) - |
| 1029 | 60 * (tz_offset % 100)); |
| 1030 | else if (skip_prefix(fmt, "z", &fmt)) |
| 1031 | strbuf_addf(&munged_fmt, "%+05d", tz_offset); |
| 1032 | else if (suppress_tz_name && skip_prefix(fmt, "Z", &fmt)) |
| 1033 | ; /* nothing */ |
| 1034 | else |
| 1035 | strbuf_addch(&munged_fmt, '%'); |
| 1036 | } |
| 1037 | fmt = munged_fmt.buf; |
| 1038 | |
| 1039 | strbuf_grow(sb, hint); |
| 1040 | len = strftime(sb->buf + sb->len, sb->alloc - sb->len, fmt, tm); |
| 1041 | |
| 1042 | if (!len) { |
| 1043 | /* |
| 1044 | * strftime reports "0" if it could not fit the result in the buffer. |
| 1045 | * Unfortunately, it also reports "0" if the requested time string |
| 1046 | * takes 0 bytes. So our strategy is to munge the format so that the |
| 1047 | * output contains at least one character, and then drop the extra |
| 1048 | * character before returning. |
| 1049 | */ |
| 1050 | strbuf_addch(&munged_fmt, ' '); |
| 1051 | while (!len) { |
| 1052 | hint *= 2; |
| 1053 | strbuf_grow(sb, hint); |
| 1054 | len = strftime(sb->buf + sb->len, sb->alloc - sb->len, |
| 1055 | munged_fmt.buf, tm); |
| 1056 | } |
| 1057 | len--; /* drop munged space */ |
| 1058 | } |
| 1059 | strbuf_release(&munged_fmt); |
| 1060 | strbuf_setlen(sb, sb->len + len); |
no test coverage detected