]> git.saurik.com Git - apple/libc.git/blob - string.subproj/strftime.c
Libc-166.tar.gz
[apple/libc.git] / string.subproj / strftime.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1989, 1993
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 */
54
55
56 #include <sys/types.h>
57 #include <sys/time.h>
58 #include <tzfile.h>
59 #include <string.h>
60
61 static char *afmt[] = {
62 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
63 };
64 static char *Afmt[] = {
65 "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
66 "Saturday",
67 };
68 static char *bfmt[] = {
69 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
70 "Oct", "Nov", "Dec",
71 };
72 static char *Bfmt[] = {
73 "January", "February", "March", "April", "May", "June", "July",
74 "August", "September", "October", "November", "December",
75 };
76
77 static size_t gsize;
78 static char *pt;
79 static int _add __P((char *));
80 static int _conv __P((int, int, int));
81 static int _secs __P((const struct tm *));
82 static size_t _fmt __P((const char *, const struct tm *));
83
84 size_t
85 strftime(s, maxsize, format, t)
86 char *s;
87 size_t maxsize;
88 const char *format;
89 const struct tm *t;
90 {
91
92 pt = s;
93 if ((gsize = maxsize) < 1)
94 return(0);
95 if (_fmt(format, t)) {
96 *pt = '\0';
97 return(maxsize - gsize);
98 }
99 return(0);
100 }
101
102 static size_t
103 _fmt(format, t)
104 register const char *format;
105 const struct tm *t;
106 {
107 for (; *format; ++format) {
108 if (*format == '%')
109 switch(*++format) {
110 case '\0':
111 --format;
112 break;
113 case 'A':
114 if (t->tm_wday < 0 || t->tm_wday > 6)
115 return(0);
116 if (!_add(Afmt[t->tm_wday]))
117 return(0);
118 continue;
119 case 'a':
120 if (t->tm_wday < 0 || t->tm_wday > 6)
121 return(0);
122 if (!_add(afmt[t->tm_wday]))
123 return(0);
124 continue;
125 case 'B':
126 if (t->tm_mon < 0 || t->tm_mon > 11)
127 return(0);
128 if (!_add(Bfmt[t->tm_mon]))
129 return(0);
130 continue;
131 case 'b':
132 case 'h':
133 if (t->tm_mon < 0 || t->tm_mon > 11)
134 return(0);
135 if (!_add(bfmt[t->tm_mon]))
136 return(0);
137 continue;
138 case 'C':
139 if (!_fmt("%a %b %e %H:%M:%S %Y", t))
140 return(0);
141 continue;
142 case 'c':
143 if (!_fmt("%m/%d/%y %H:%M:%S", t))
144 return(0);
145 continue;
146 case 'D':
147 if (!_fmt("%m/%d/%y", t))
148 return(0);
149 continue;
150 case 'd':
151 if (!_conv(t->tm_mday, 2, '0'))
152 return(0);
153 continue;
154 case 'e':
155 if (!_conv(t->tm_mday, 2, ' '))
156 return(0);
157 continue;
158 case 'H':
159 if (!_conv(t->tm_hour, 2, '0'))
160 return(0);
161 continue;
162 case 'I':
163 if (!_conv(t->tm_hour % 12 ?
164 t->tm_hour % 12 : 12, 2, '0'))
165 return(0);
166 continue;
167 case 'j':
168 if (!_conv(t->tm_yday + 1, 3, '0'))
169 return(0);
170 continue;
171 case 'k':
172 if (!_conv(t->tm_hour, 2, ' '))
173 return(0);
174 continue;
175 case 'l':
176 if (!_conv(t->tm_hour % 12 ?
177 t->tm_hour % 12 : 12, 2, ' '))
178 return(0);
179 continue;
180 case 'M':
181 if (!_conv(t->tm_min, 2, '0'))
182 return(0);
183 continue;
184 case 'm':
185 if (!_conv(t->tm_mon + 1, 2, '0'))
186 return(0);
187 continue;
188 case 'n':
189 if (!_add("\n"))
190 return(0);
191 continue;
192 case 'p':
193 if (!_add(t->tm_hour >= 12 ? "PM" : "AM"))
194 return(0);
195 continue;
196 case 'R':
197 if (!_fmt("%H:%M", t))
198 return(0);
199 continue;
200 case 'r':
201 if (!_fmt("%I:%M:%S %p", t))
202 return(0);
203 continue;
204 case 'S':
205 if (!_conv(t->tm_sec, 2, '0'))
206 return(0);
207 continue;
208 case 's':
209 if (!_secs(t))
210 return(0);
211 continue;
212 case 'T':
213 case 'X':
214 if (!_fmt("%H:%M:%S", t))
215 return(0);
216 continue;
217 case 't':
218 if (!_add("\t"))
219 return(0);
220 continue;
221 case 'U':
222 if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
223 2, '0'))
224 return(0);
225 continue;
226 case 'W':
227 if (!_conv((t->tm_yday + 7 -
228 (t->tm_wday ? (t->tm_wday - 1) : 6))
229 / 7, 2, '0'))
230 return(0);
231 continue;
232 case 'w':
233 if (!_conv(t->tm_wday, 1, '0'))
234 return(0);
235 continue;
236 case 'x':
237 if (!_fmt("%m/%d/%y", t))
238 return(0);
239 continue;
240 case 'y':
241 if (!_conv((t->tm_year + TM_YEAR_BASE)
242 % 100, 2, '0'))
243 return(0);
244 continue;
245 case 'Y':
246 if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0'))
247 return(0);
248 continue;
249 case 'Z':
250 if (!t->tm_zone || !_add(t->tm_zone))
251 return(0);
252 continue;
253 case '%':
254 /*
255 * X311J/88-090 (4.12.3.5): if conversion char is
256 * undefined, behavior is undefined. Print out the
257 * character itself as printf(3) does.
258 */
259 default:
260 break;
261 }
262 if (!gsize--)
263 return(0);
264 *pt++ = *format;
265 }
266 return(gsize);
267 }
268
269 static int
270 _secs(t)
271 const struct tm *t;
272 {
273 static char buf[15];
274 register time_t s;
275 register char *p;
276 struct tm tmp;
277
278 /* Make a copy, mktime(3) modifies the tm struct. */
279 tmp = *t;
280 s = mktime(&tmp);
281 for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10)
282 *p-- = s % 10 + '0';
283 return(_add(++p));
284 }
285
286 static int
287 _conv(n, digits, pad)
288 int n, digits, pad;
289 {
290 static char buf[10];
291 register char *p;
292
293 for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
294 *p-- = n % 10 + '0';
295 while (p > buf && digits-- > 0)
296 *p-- = pad;
297 return(_add(++p));
298 }
299
300 static int
301 _add(str)
302 register char *str;
303 {
304 for (;; ++pt, --gsize) {
305 if (!gsize)
306 return(0);
307 if (!(*pt = *str++))
308 return(1);
309 }
310 }