:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / lib / crtdll / time / strftime.c
1 /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
2 #include <crtdll/string.h>
3 #include <crtdll/time.h>
4 #include <crtdll/stdlib.h>
5 #include <crtdll/wchar.h>
6
7 #define TM_YEAR_BASE 1900
8
9 static const char *afmt[] = {
10   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
11 };
12 static const char *Afmt[] = {
13   "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
14   "Saturday",
15 };
16 static const char *bfmt[] = {
17   "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
18   "Oct", "Nov", "Dec",
19 };
20 static const char *Bfmt[] = {
21   "January", "February", "March", "April", "May", "June", "July",
22   "August", "September", "October", "November", "December",
23 };
24
25 static size_t gsize;
26 static char *pt;
27
28 static int
29 _add(const char *str)
30 {
31   for (;; ++pt, --gsize)
32   {
33     if (!gsize)
34       return 0;
35     if (!(*pt = *str++))
36       return 1;
37   }
38 }
39
40 static int
41 _conv(int n, int digits, char pad)
42 {
43   static char buf[10];
44   char *p;
45
46   for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
47     *p-- = n % 10 + '0';
48   while (p > buf && digits-- > 0)
49     *p-- = pad;
50   return _add(++p);
51 }
52
53 static size_t
54 _fmt(const char *format, const struct tm *t)
55 {
56   for (; *format; ++format)
57   {
58     if (*format == '%') {
59         if (*(format+1) == '#' ) {format++;}
60
61       switch(*++format)
62       {
63       case '\0':
64         --format;
65         break;
66       case 'A':
67         if (t->tm_wday < 0 || t->tm_wday > 6)
68           return 0;
69         if (!_add(Afmt[t->tm_wday]))
70           return 0;
71         continue;
72       case 'a':
73         if (t->tm_wday < 0 || t->tm_wday > 6)
74           return 0;
75         if (!_add(afmt[t->tm_wday]))
76           return 0;
77         continue;
78       case 'B':
79         if (t->tm_mon < 0 || t->tm_mon > 11)
80           return 0;
81         if (!_add(Bfmt[t->tm_mon]))
82           return 0;
83         continue;
84       case 'b':
85       case 'h':
86         if (t->tm_mon < 0 || t->tm_mon > 11)
87           return 0;
88         if (!_add(bfmt[t->tm_mon]))
89           return 0;
90         continue;
91       case 'C':
92         if (!_fmt("%a %b %e %H:%M:%S %Y", t))
93           return 0;
94         continue;
95       case 'c':
96         if (!_fmt("%m/%d/%y %H:%M:%S", t))
97           return 0;
98         continue;
99       case 'e':
100         if (!_conv(t->tm_mday, 2, ' '))
101           return 0;
102         continue;
103       case 'D':
104         if (!_fmt("%m/%d/%y", t))
105           return 0;
106         continue;
107       case 'd':
108         if (!_conv(t->tm_mday, 2, '0'))
109           return 0;
110         continue;
111       case 'H':
112         if (!_conv(t->tm_hour, 2, '0'))
113           return 0;
114         continue;
115       case 'I':
116         if (!_conv(t->tm_hour % 12 ?
117                    t->tm_hour % 12 : 12, 2, '0'))
118           return 0;
119         continue;
120       case 'j':
121         if (!_conv(t->tm_yday + 1, 3, '0'))
122           return 0;
123         continue;
124       case 'k':
125         if (!_conv(t->tm_hour, 2, ' '))
126           return 0;
127         continue;
128       case 'l':
129         if (!_conv(t->tm_hour % 12 ?
130                    t->tm_hour % 12 : 12, 2, ' '))
131           return 0;
132         continue;
133       case 'M':
134         if (!_conv(t->tm_min, 2, '0'))
135           return 0;
136         continue;
137       case 'm':
138         if (!_conv(t->tm_mon + 1, 2, '0'))
139           return 0;
140         continue;
141       case 'n':
142         if (!_add("\n"))
143           return 0;
144         continue;
145       case 'p':
146         if (!_add(t->tm_hour >= 12 ? "PM" : "AM"))
147           return 0;
148         continue;
149       case 'R':
150         if (!_fmt("%H:%M", t))
151           return 0;
152         continue;
153       case 'r':
154         if (!_fmt("%I:%M:%S %p", t))
155           return 0;
156         continue;
157       case 'S':
158         if (!_conv(t->tm_sec, 2, '0'))
159           return 0;
160         continue;
161       case 'T':
162       case 'X':
163         if (!_fmt("%H:%M:%S", t))
164           return 0;
165         continue;
166       case 't':
167         if (!_add("\t"))
168           return 0;
169         continue;
170       case 'U':
171         if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
172                    2, '0'))
173           return 0;
174         continue;
175       case 'W':
176         if (!_conv((t->tm_yday + 7 -
177                     (t->tm_wday ? (t->tm_wday - 1) : 6))
178                    / 7, 2, '0'))
179           return 0;
180         continue;
181       case 'w':
182         if (!_conv(t->tm_wday, 1, '0'))
183           return 0;
184         continue;
185       case 'x':
186         if (!_fmt("%m/%d/%y", t))
187           return 0;
188         continue;
189       case 'y':
190         if (!_conv((t->tm_year + TM_YEAR_BASE)
191                    % 100, 2, '0'))
192           return 0;
193         continue;
194       case 'Y':
195         if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0'))
196           return 0;
197         continue;
198       case 'Z':
199         if (!t->tm_zone || !_add(t->tm_zone))
200           return 0;
201         continue;
202       case '%':
203         /*
204          * X311J/88-090 (4.12.3.5): if conversion char is
205          * undefined, behavior is undefined.  Print out the
206          * character itself as printf(3) does.
207          */
208       default:
209         break;
210       }
211     }
212     if (!gsize--)
213       return 0;
214     *pt++ = *format;
215   }
216   return gsize;
217 }
218
219 size_t
220 strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
221 {
222   pt = s;
223   if ((gsize = maxsize) < 1)
224     return 0;
225   if (_fmt(format, t))
226   {
227     *pt = '\0';
228     return maxsize - gsize;
229   }
230   return 0;
231 }
232
233 size_t
234 wcsftime(wchar_t *s, size_t maxsize, const wchar_t *format, const struct tm *t)
235 {
236   char *x;
237   char *f;
238   int i,j;
239   x = malloc(maxsize);
240   j = wcslen(format);
241   f = malloc(j+1);
242   for(i=0;i<j;i++)
243         f[i] = (char)*format;
244   f[i] = 0;
245   pt = x;
246   if ((gsize = maxsize) < 1)
247     return 0;
248   if (_fmt(f, t))
249   {
250     *pt = '\0';
251     free(f);
252     for(i=0;i<maxsize;i++)
253         s[i] = (wchar_t)x[i];
254     s[i] = 0;
255     free(x);
256     return maxsize - gsize;
257   }
258   for(i=0;i<maxsize;i++)
259         s[i] = (wchar_t)x[i];
260   s[i] = 0;
261   free(f);
262   free(x);
263   return 0;
264 }