]> git.sur5r.net Git - cc65/blob - libsrc/common/strftime.c
467d13516452c958f896503434a2dbf77298d289
[cc65] / libsrc / common / strftime.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                strftime.c                                 */
4 /*                                                                           */
5 /*      Convert broken down time to a string in a user specified format      */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002      Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37 #include <stdio.h>
38 #include <time.h>
39
40
41
42 /* Use static local variables for speed */
43 #pragma staticlocals (on);
44
45
46
47 /*****************************************************************************/
48 /*                                   Code                                    */
49 /*****************************************************************************/
50
51
52
53 size_t __fastcall__ strftime (char* buf, size_t bufsize, const char* format,
54                               const struct tm* tm)
55 {
56     static const char* days[7] = {
57         "Sunday",   "Monday", "Tuesday", "Wednesday",
58         "Thursday", "Friday", "Saturday"
59     };
60     static const char* months[12] = {
61         "January", "February", "March", "April", "May", "June",
62         "July", "August", "September", "October", "November", "December"
63     };
64
65     unsigned    count;
66     unsigned    len;
67     char        c;
68     char        arg[40];
69     const char* argptr;
70     unsigned    week;
71
72     /* Copy until we reach the end of the format string or a format specifier */
73     count = 0;
74     while (1) {
75         if (count >= bufsize) {
76             /* Not enough buffer space available */
77             return 0;
78         }
79         if ((c = *format++) == '\0') {
80             /* End of format string reached */
81             *buf = '\0';
82             return count;
83         }
84         if (c == '%') {
85             /* Format specifier */
86             argptr = arg;
87             switch (*format++) {
88
89                 case '%':
90                     arg[0] = '%';
91                     arg[1] = '\0';
92                     break;
93
94                 case 'A':
95                     argptr = days[tm->tm_wday];
96                     break;
97
98                 case 'B':
99                     argptr = months[tm->tm_mon];
100                     break;
101
102                 case 'D':
103                     sprintf (arg, "%02d/%02d/%02d", tm->tm_mon + 1,
104                              tm->tm_mday, tm->tm_year % 100);
105                     break;
106
107                 case 'F':
108                     /* C99 */
109                     sprintf (arg, "%04d-%02d-%02d", tm->tm_year + 1900,
110                              tm->tm_mon + 1, tm->tm_mday);
111                     break;
112
113                 case 'H':
114                     sprintf (arg, "%02d", tm->tm_hour);
115                     break;
116
117                 case 'I':
118                     sprintf (arg, "%02d", tm->tm_hour % 12);
119                     break;
120
121                 case 'M':
122                     sprintf (arg, "%02d", tm->tm_min);
123                     break;
124
125                 case 'P':
126                     /* GNU extension */
127                     argptr = (tm->tm_hour >= 12)? "pm" : "am";
128                     break;
129
130                 case 'S':
131                     sprintf (arg, "%02d", tm->tm_sec);
132                     break;
133
134                 case 'U':
135                     week = tm->tm_yday / 7;
136                     if (tm->tm_mday % 7 > tm->tm_wday) {
137                         ++week;
138                     }
139                     sprintf (arg, "%02u", week);
140                     break;
141
142                 case 'W':
143                     /* ### This one is buggy */
144                     week = tm->tm_yday / 7;
145                     if (tm->tm_mday % 7 > tm->tm_wday) {
146                         ++week;
147                     }
148                     sprintf (arg, "%2u", week);
149                     break;
150
151                 case 'X':
152                     sprintf (arg, "%02d:%02d:%02d", tm->tm_hour,
153                              tm->tm_min, tm->tm_sec);
154                     break;
155
156                 case 'Y':
157                     sprintf (arg, "%4d", tm->tm_year + 1900);
158                     break;
159
160                 case 'Z':
161                     argptr = tm->tm_isdst? _tz.dstname : _tz.tzname;
162                     break;
163
164                 case 'a':
165                     sprintf (arg, "%.3s", days[tm->tm_wday]);
166                     break;
167
168                 case 'b':
169                     sprintf (arg, "%.3s", months[tm->tm_mon]);
170                     break;
171
172                 case 'c':
173                     sprintf (arg, "%.3s %.3s%3d %02d:%02d:%02d %d",
174                              days[tm->tm_wday], months[tm->tm_mon],
175                              tm->tm_mday, tm->tm_hour, tm->tm_min,
176                              tm->tm_sec, tm->tm_year + 1900);
177                     break;
178
179                 case 'd':
180                     sprintf (arg, "%02d", tm->tm_mday);
181                     break;
182
183                 case 'j':
184                     sprintf (arg, "%03d", tm->tm_yday + 1);
185                     break;
186
187                 case 'm':
188                     sprintf (arg, "%02d", tm->tm_mon + 1);
189                     break;
190
191                 case 'p':
192                     argptr = (tm->tm_hour >= 12)? "PM" : "AM";
193                     break;
194
195                 case 'w':
196                     sprintf (arg, "%d", tm->tm_wday);
197                     break;
198
199                 case 'x':
200                     sprintf (arg, "%04d-%02d-%02d", tm->tm_year + 1900,
201                              tm->tm_mon + 1, tm->tm_mday);
202                     break;
203
204                 case 'y':
205                     sprintf (arg, "%02d", tm->tm_year % 100);
206                     break;
207
208                 default:
209                     /* Unknown format specifier, convert to empty string */
210                     arg[0] = '\0';
211                     break;
212             }
213
214             /* Check if we have enough space to copy the argument string */
215             len = strlen (argptr);
216             count += len;
217             if (count < bufsize) {
218                 memcpy (buf, argptr, len);
219                 buf += len;
220             }
221
222         } else {
223
224             /* No format character, just copy */
225             *buf++ = c;
226             ++count;
227
228         }
229     }
230 }
231
232
233