initial check-in, version 0.5.0
[musl] / src / time / strftime.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <langinfo.h>
4 #include <time.h>
5 #include "__time.h"
6
7 // FIXME: integer overflows
8
9 const char *__langinfo(nl_item);
10
11 size_t strftime(char *s, size_t n, const char *f, const struct tm *tm)
12 {
13         nl_item item;
14         int val;
15         const char *fmt;
16         size_t l;
17         for (l=0; *f && l<n; f++) {
18                 if (*f == '%') {
19 do_fmt:
20                 switch (*++f) {
21                 case '%':
22                         goto literal;
23                 case 'E':
24                 case 'O':
25                         goto do_fmt;
26                 case 'a':
27                         item = ABDAY_1 + tm->tm_wday;
28                         goto nl_strcat;
29                 case 'A':
30                         item = DAY_1 + tm->tm_wday;
31                         goto nl_strcat;
32                 case 'h':
33                 case 'b':
34                         item = ABMON_1 + tm->tm_mon;
35                         goto nl_strcat;
36                 case 'B':
37                         item = MON_1 + tm->tm_mon;
38                         goto nl_strcat;
39                 case 'c':
40                         item = D_T_FMT;
41                         goto nl_strftime;
42                 case 'C':
43                         val = (1900+tm->tm_year) / 100;
44                         fmt = "%02d";
45                         goto number;
46                 case 'd':
47                         val = tm->tm_mday;
48                         fmt = "%02d";
49                         goto number;
50                 case 'D':
51                         fmt = "%m/%d/%y";
52                         goto recu_strftime;
53                 case 'e':
54                         val = tm->tm_mday;
55                         fmt = "%2d";
56                         goto number;
57                 case 'F':
58                         fmt = "%Y-%m-%d";
59                         goto recu_strftime;
60                 case 'g':
61                         // FIXME
62                         val = 0; //week_based_year(tm)%100;
63                         fmt = "%02d";
64                         goto number;
65                 case 'G':
66                         // FIXME
67                         val = 0; //week_based_year(tm);
68                         fmt = "%04d";
69                         goto number;
70                 case 'H':
71                         val = tm->tm_hour;
72                         fmt = "%02d";
73                         goto number;
74                 case 'I':
75                         val = tm->tm_hour;
76                         if (!val) val = 12;
77                         else if (val > 12) val -= 12;
78                         fmt = "%02d";
79                         goto number;
80                 case 'j':
81                         val = tm->tm_yday+1;
82                         fmt = "%03d";
83                         goto number;
84                 case 'm':
85                         val = tm->tm_mon+1;
86                         fmt = "%02d";
87                         goto number;
88                 case 'M':
89                         val = tm->tm_min;
90                         fmt = "%02d";
91                         goto number;
92                 case 'n':
93                         s[l++] = '\n';
94                         continue;
95                 case 'p':
96                         item = tm->tm_hour >= 12 ? PM_STR : AM_STR;
97                         goto nl_strcat;
98                 case 'r':
99                         item = T_FMT_AMPM;
100                         goto nl_strftime;
101                 case 'R':
102                         fmt = "%H:%M";
103                         goto recu_strftime;
104                 case 'S':
105                         val = tm->tm_sec;
106                         fmt = "%02d";
107                         goto number;
108                 case 't':
109                         s[l++] = '\t';
110                         continue;
111                 case 'T':
112                         fmt = "%H:%M:%S";
113                         goto recu_strftime;
114                 case 'u':
115                         val = tm->tm_wday ? tm->tm_wday : 7;
116                         fmt = "%d";
117                         goto number;
118                 case 'U':
119                 case 'V':
120                 case 'W':
121                         // FIXME: week number mess..
122                         continue;
123                 case 'w':
124                         val = tm->tm_wday;
125                         fmt = "%d";
126                         goto number;
127                 case 'x':
128                         item = D_FMT;
129                         goto nl_strftime;
130                 case 'X':
131                         item = T_FMT;
132                         goto nl_strftime;
133                 case 'y':
134                         val = tm->tm_year % 100;
135                         fmt = "%02d";
136                         goto number;
137                 case 'Y':
138                         val = tm->tm_year + 1900;
139                         fmt = "%04d";
140                         goto number;
141                 case 'z':
142                         if (tm->tm_isdst < 0) continue;
143                         val = -__timezone - (tm->tm_isdst ? __dst_offset : 0);
144                         l += snprintf(s+l, n-l, "%+.2d%.2d", val/3600, abs(val%3600)/60);
145                         continue;
146                 case 'Z':
147                         if (tm->tm_isdst < 0 || !__tzname[0] || !__tzname[0][0])
148                                 continue;
149                         l += snprintf(s+l, n-l, "%s", __tzname[!!tm->tm_isdst]);
150                         continue;
151                 default:
152                         return 0;
153                 }
154                 }
155 literal:
156                 s[l++] = *f;
157                 continue;
158 number:
159                 l += snprintf(s+l, n-l, fmt, val);
160                 continue;
161 nl_strcat:
162                 l += snprintf(s+l, n-l, "%s", __langinfo(item));
163                 continue;
164 nl_strftime:
165                 fmt = __langinfo(item);
166 recu_strftime:
167                 l += strftime(s+l, n-l, fmt, tm);
168         }
169         if (l >= n) return 0;
170         s[l] = 0;
171         return l;
172 }