summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/time/strftime.c312
1 files changed, 161 insertions, 151 deletions
diff --git a/src/time/strftime.c b/src/time/strftime.c
index 3f0ec3e3..87e87d50 100644
--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -44,168 +44,178 @@ static int week_num(const struct tm *tm)
return val;
}
-size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc)
+size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct tm *restrict, locale_t);
+
+int __strftime_fmt_1(char *s, size_t n, int f, const struct tm *tm, locale_t loc)
{
nl_item item;
int val;
const char *fmt;
size_t l;
- for (l=0; *f && l<n; f++) {
- if (*f != '%') {
-literal:
- s[l++] = *f;
- continue;
- }
-do_fmt:
- switch (*++f) {
- case '%':
- goto literal;
- case 'E':
- case 'O':
- goto do_fmt;
- case 'a':
- item = ABDAY_1 + tm->tm_wday;
- goto nl_strcat;
- case 'A':
- item = DAY_1 + tm->tm_wday;
- goto nl_strcat;
- case 'h':
- case 'b':
- item = ABMON_1 + tm->tm_mon;
- goto nl_strcat;
- case 'B':
- item = MON_1 + tm->tm_mon;
- goto nl_strcat;
- case 'c':
- item = D_T_FMT;
- goto nl_strftime;
- case 'C':
- val = (1900+tm->tm_year) / 100;
- fmt = "%02d";
- goto number;
- case 'd':
- val = tm->tm_mday;
- fmt = "%02d";
- goto number;
- case 'D':
- fmt = "%m/%d/%y";
- goto recu_strftime;
- case 'e':
- val = tm->tm_mday;
- fmt = "%2d";
- goto number;
- case 'F':
- fmt = "%Y-%m-%d";
- goto recu_strftime;
- case 'g':
- case 'G':
- fmt = "%04d";
- val = tm->tm_year + 1900;
- if (tm->tm_yday < 3 && week_num(tm) != 1) val--;
- else if (tm->tm_yday > 360 && week_num(tm) == 1) val++;
- if (*f=='g') {
- fmt = "%02d";
- val %= 100;
- }
- goto number;
- case 'H':
- val = tm->tm_hour;
- fmt = "%02d";
- goto number;
- case 'I':
- val = tm->tm_hour;
- if (!val) val = 12;
- else if (val > 12) val -= 12;
- fmt = "%02d";
- goto number;
- case 'j':
- val = tm->tm_yday+1;
- fmt = "%03d";
- goto number;
- case 'm':
- val = tm->tm_mon+1;
- fmt = "%02d";
- goto number;
- case 'M':
- val = tm->tm_min;
- fmt = "%02d";
- goto number;
- case 'n':
- s[l++] = '\n';
- continue;
- case 'p':
- item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
- goto nl_strcat;
- case 'r':
- item = T_FMT_AMPM;
- goto nl_strftime;
- case 'R':
- fmt = "%H:%M";
- goto recu_strftime;
- case 'S':
- val = tm->tm_sec;
- fmt = "%02d";
- goto number;
- case 't':
- s[l++] = '\t';
- continue;
- case 'T':
- fmt = "%H:%M:%S";
- goto recu_strftime;
- case 'u':
- val = tm->tm_wday ? tm->tm_wday : 7;
- fmt = "%d";
- goto number;
- case 'U':
- val = (tm->tm_yday + 7 - tm->tm_wday) / 7;
- fmt = "%02d";
- goto number;
- case 'W':
- val = (tm->tm_yday + 7 - (tm->tm_wday+6)%7) / 7;
- fmt = "%02d";
- goto number;
- case 'V':
- val = week_num(tm);
- fmt = "%02d";
- goto number;
- case 'w':
- val = tm->tm_wday;
- fmt = "%d";
- goto number;
- case 'x':
- item = D_FMT;
- goto nl_strftime;
- case 'X':
- item = T_FMT;
- goto nl_strftime;
- case 'y':
- val = tm->tm_year % 100;
+
+ if (n<2) return 0;
+
+ switch (f) {
+ case 'a':
+ item = ABDAY_1 + tm->tm_wday;
+ goto nl_strcat;
+ case 'A':
+ item = DAY_1 + tm->tm_wday;
+ goto nl_strcat;
+ case 'h':
+ case 'b':
+ item = ABMON_1 + tm->tm_mon;
+ goto nl_strcat;
+ case 'B':
+ item = MON_1 + tm->tm_mon;
+ goto nl_strcat;
+ case 'c':
+ item = D_T_FMT;
+ goto nl_strftime;
+ case 'C':
+ val = (1900+tm->tm_year) / 100;
+ fmt = "%02d";
+ goto number;
+ case 'd':
+ val = tm->tm_mday;
+ fmt = "%02d";
+ goto number;
+ case 'D':
+ fmt = "%m/%d/%y";
+ goto recu_strftime;
+ case 'e':
+ val = tm->tm_mday;
+ fmt = "%2d";
+ goto number;
+ case 'F':
+ fmt = "%Y-%m-%d";
+ goto recu_strftime;
+ case 'g':
+ case 'G':
+ fmt = "%04d";
+ val = tm->tm_year + 1900;
+ if (tm->tm_yday < 3 && week_num(tm) != 1) val--;
+ else if (tm->tm_yday > 360 && week_num(tm) == 1) val++;
+ if (f=='g') {
fmt = "%02d";
- goto number;
- case 'Y':
- val = tm->tm_year + 1900;
- fmt = "%04d";
- goto number;
- case 'z':
- val = -tm->__tm_gmtoff;
- l += snprintf(s+l, n-l, "%+.2d%.2d", val/3600, abs(val%3600)/60);
- continue;
- case 'Z':
- l += snprintf(s+l, n-l, "%s", tm->__tm_zone);
- continue;
- default:
- return 0;
+ val %= 100;
}
+ goto number;
+ case 'H':
+ val = tm->tm_hour;
+ fmt = "%02d";
+ goto number;
+ case 'I':
+ val = tm->tm_hour;
+ if (!val) val = 12;
+ else if (val > 12) val -= 12;
+ fmt = "%02d";
+ goto number;
+ case 'j':
+ val = tm->tm_yday+1;
+ fmt = "%03d";
+ goto number;
+ case 'm':
+ val = tm->tm_mon+1;
+ fmt = "%02d";
+ goto number;
+ case 'M':
+ val = tm->tm_min;
+ fmt = "%02d";
+ goto number;
+ case 'n':
+ s[0] = '\n';
+ s[1] = 0;
+ return 1;
+ case 'p':
+ item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
+ goto nl_strcat;
+ case 'r':
+ item = T_FMT_AMPM;
+ goto nl_strftime;
+ case 'R':
+ fmt = "%H:%M";
+ goto recu_strftime;
+ case 'S':
+ val = tm->tm_sec;
+ fmt = "%02d";
+ goto number;
+ case 't':
+ s[0] = '\t';
+ s[1] = 0;
+ return 1;
+ case 'T':
+ fmt = "%H:%M:%S";
+ goto recu_strftime;
+ case 'u':
+ val = tm->tm_wday ? tm->tm_wday : 7;
+ fmt = "%d";
+ goto number;
+ case 'U':
+ val = (tm->tm_yday + 7 - tm->tm_wday) / 7;
+ fmt = "%02d";
+ goto number;
+ case 'W':
+ val = (tm->tm_yday + 7 - (tm->tm_wday+6)%7) / 7;
+ fmt = "%02d";
+ goto number;
+ case 'V':
+ val = week_num(tm);
+ fmt = "%02d";
+ goto number;
+ case 'w':
+ val = tm->tm_wday;
+ fmt = "%d";
+ goto number;
+ case 'x':
+ item = D_FMT;
+ goto nl_strftime;
+ case 'X':
+ item = T_FMT;
+ goto nl_strftime;
+ case 'y':
+ val = tm->tm_year % 100;
+ fmt = "%02d";
+ goto number;
+ case 'Y':
+ val = tm->tm_year + 1900;
+ fmt = "%04d";
+ goto number;
+ case 'z':
+ val = -tm->__tm_gmtoff;
+ return snprintf(s, n, "%+.2d%.2d", val/3600, abs(val%3600)/60);
+ case 'Z':
+ return snprintf(s, n, "%s", tm->__tm_zone);
+ case '%':
+ s[0] = '%';
+ s[1] = 0;
+ return 1;
+ default:
+ return 0;
+ }
number:
- l += snprintf(s+l, n-l, fmt, val);
- continue;
+ return snprintf(s, n, fmt, val);
nl_strcat:
- l += snprintf(s+l, n-l, "%s", __nl_langinfo_l(item, loc));
- continue;
+ return snprintf(s, n, "%s", __nl_langinfo_l(item, loc));
nl_strftime:
- fmt = __nl_langinfo_l(item, loc);
+ fmt = __nl_langinfo_l(item, loc);
recu_strftime:
- l += __strftime_l(s+l, n-l, fmt, tm, loc);
+ return __strftime_l(s, n, fmt, tm, loc);
+}
+
+size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const struct tm *restrict tm, locale_t loc)
+{
+ size_t l, k;
+ for (l=0; *f && l<n; f++) {
+ if (*f != '%') {
+ s[l++] = *f;
+ continue;
+ }
+ f++;
+ if (*f == 'E' || *f == 'O') f++;
+ k = __strftime_fmt_1(s+l, n-l, *f, tm, loc);
+ if (!k) return 0;
+ l += k;
}
if (l >= n) return 0;
s[l] = 0;