summaryrefslogtreecommitdiff
path: root/src/lib/libc/string/strftime.c
diff options
context:
space:
mode:
authorderaadt <>1995-10-18 08:42:23 +0000
committerderaadt <>1995-10-18 08:42:23 +0000
commit0527d29da443886d92e9a418180c5b25a5f8d270 (patch)
tree86b3a64928451a669cefa27900e5884036b4e349 /src/lib/libc/string/strftime.c
downloadopenbsd-0527d29da443886d92e9a418180c5b25a5f8d270.tar.gz
openbsd-0527d29da443886d92e9a418180c5b25a5f8d270.tar.bz2
openbsd-0527d29da443886d92e9a418180c5b25a5f8d270.zip
initial import of NetBSD tree
Diffstat (limited to 'src/lib/libc/string/strftime.c')
-rw-r--r--src/lib/libc/string/strftime.c317
1 files changed, 317 insertions, 0 deletions
diff --git a/src/lib/libc/string/strftime.c b/src/lib/libc/string/strftime.c
new file mode 100644
index 0000000000..fffa9ecbb0
--- /dev/null
+++ b/src/lib/libc/string/strftime.c
@@ -0,0 +1,317 @@
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35/*static char *sccsid = "from: @(#)strftime.c 5.11 (Berkeley) 2/24/91";*/
36static char *rcsid = "$Id: strftime.c,v 1.1.1.1 1995/10/18 08:42:22 deraadt Exp $";
37#endif /* LIBC_SCCS and not lint */
38
39#include <sys/localedef.h>
40#include <locale.h>
41#include <string.h>
42#include <tzfile.h>
43#include <time.h>
44
45static size_t gsize;
46static char *pt;
47static int _add(), _conv(), _secs();
48static size_t _fmt();
49
50size_t
51strftime(s, maxsize, format, t)
52 char *s;
53 size_t maxsize;
54 const char *format;
55 const struct tm *t;
56{
57 tzset();
58
59 pt = s;
60 if ((gsize = maxsize) < 1)
61 return(0);
62 if (_fmt(format, t)) {
63 *pt = '\0';
64 return(maxsize - gsize);
65 }
66 return(0);
67}
68
69#define SUN_WEEK(t) (((t)->tm_yday + 7 - \
70 ((t)->tm_wday)) / 7)
71#define MON_WEEK(t) (((t)->tm_yday + 7 - \
72 ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7)
73static size_t
74_fmt(format, t)
75 register char *format;
76 struct tm *t;
77{
78 for (; *format; ++format) {
79 if (*format == '%') {
80 ++format;
81 if (*format == 'E') {
82 /* Alternate Era */
83 ++format;
84 } else if (*format == 'O') {
85 /* Alternate numeric symbols */
86 ++format;
87 }
88 switch(*format) {
89 case '\0':
90 --format;
91 break;
92 case 'A':
93 if (t->tm_wday < 0 || t->tm_wday > 6)
94 return(0);
95 if (!_add(_CurrentTimeLocale->day[t->tm_wday]))
96 return(0);
97 continue;
98 case 'a':
99 if (t->tm_wday < 0 || t->tm_wday > 6)
100 return(0);
101 if (!_add(_CurrentTimeLocale->abday[t->tm_wday]))
102 return(0);
103 continue;
104 case 'B':
105 if (t->tm_mon < 0 || t->tm_mon > 11)
106 return(0);
107 if (!_add(_CurrentTimeLocale->mon[t->tm_mon]))
108 return(0);
109 continue;
110 case 'b':
111 case 'h':
112 if (t->tm_mon < 0 || t->tm_mon > 11)
113 return(0);
114 if (!_add(_CurrentTimeLocale->abmon[t->tm_mon]))
115 return(0);
116 continue;
117 case 'C':
118 if (!_conv((t->tm_year + TM_YEAR_BASE) / 100,
119 2, '0'))
120 return(0);
121 continue;
122 case 'c':
123 if (!_fmt(_CurrentTimeLocale->d_t_fmt, t))
124 return(0);
125 continue;
126 case 'D':
127 if (!_fmt("%m/%d/%y", t))
128 return(0);
129 continue;
130 case 'd':
131 if (!_conv(t->tm_mday, 2, '0'))
132 return(0);
133 continue;
134 case 'e':
135 if (!_conv(t->tm_mday, 2, ' '))
136 return(0);
137 continue;
138 case 'H':
139 if (!_conv(t->tm_hour, 2, '0'))
140 return(0);
141 continue;
142 case 'I':
143 if (!_conv(t->tm_hour % 12 ?
144 t->tm_hour % 12 : 12, 2, '0'))
145 return(0);
146 continue;
147 case 'j':
148 if (!_conv(t->tm_yday + 1, 3, '0'))
149 return(0);
150 continue;
151 case 'k':
152 if (!_conv(t->tm_hour, 2, ' '))
153 return(0);
154 continue;
155 case 'l':
156 if (!_conv(t->tm_hour % 12 ?
157 t->tm_hour % 12: 12, 2, ' '))
158 return(0);
159 continue;
160 case 'M':
161 if (!_conv(t->tm_min, 2, '0'))
162 return(0);
163 continue;
164 case 'm':
165 if (!_conv(t->tm_mon + 1, 2, '0'))
166 return(0);
167 continue;
168 case 'n':
169 if (!_add("\n"))
170 return(0);
171 continue;
172 case 'p':
173 if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour >= 12]))
174 return(0);
175 continue;
176 case 'R':
177 if (!_fmt("%H:%M", t))
178 return(0);
179 continue;
180 case 'r':
181 if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t))
182 return(0);
183 continue;
184 case 'S':
185 if (!_conv(t->tm_sec, 2, '0'))
186 return(0);
187 continue;
188 case 's':
189 if (!_secs(t))
190 return(0);
191 continue;
192 case 'T':
193 if (!_fmt("%H:%M:%S", t))
194 return(0);
195 continue;
196 case 't':
197 if (!_add("\t"))
198 return(0);
199 continue;
200 case 'U':
201 if (!_conv(SUN_WEEK(t), 2, '0'))
202 return(0);
203 continue;
204 case 'u':
205 if (!_conv(t->tm_wday ? t->tm_wday : 7, 2, '0'))
206 return(0);
207 continue;
208 case 'V':
209 {
210 /* ISO 8601 Week Of Year:
211 If the week (Monday - Sunday) containing
212 January 1 has four or more days in the new
213 year, then it is week 1; otherwise it is
214 week 53 of the previous year and the next
215 week is week one. */
216
217 int week = MON_WEEK(t);
218
219 if (((t->tm_yday + 7 - (t->tm_wday + 1)) % 7) >= 4) {
220 week++;
221 } else if (week == 0) {
222 week = 53;
223 }
224
225 if (!_conv(week, 2, '0'))
226 return(0);
227 continue;
228 }
229 case 'W':
230 if (!_conv(MON_WEEK(t), 2, '0'))
231 return(0);
232 continue;
233 case 'w':
234 if (!_conv(t->tm_wday, 1, '0'))
235 return(0);
236 continue;
237 case 'x':
238 if (!_fmt(_CurrentTimeLocale->d_fmt, t))
239 return(0);
240 continue;
241 case 'X':
242 if (!_fmt(_CurrentTimeLocale->t_fmt, t))
243 return(0);
244 continue;
245 case 'y':
246 if (!_conv((t->tm_year + TM_YEAR_BASE) % 100,
247 2, '0'))
248 return(0);
249 continue;
250 case 'Y':
251 if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0'))
252 return(0);
253 continue;
254 case 'Z':
255 if (t->tm_zone && !_add(t->tm_zone))
256 return(0);
257 continue;
258 case '%':
259 /*
260 * X311J/88-090 (4.12.3.5): if conversion char is
261 * undefined, behavior is undefined. Print out the
262 * character itself as printf(3) does.
263 */
264 default:
265 break;
266 }
267 }
268 if (!gsize--)
269 return(0);
270 *pt++ = *format;
271 }
272 return(gsize);
273}
274
275static
276_secs(t)
277 struct tm *t;
278{
279 static char buf[15];
280 register time_t s;
281 register char *p;
282 struct tm tmp;
283
284 /* Make a copy, mktime(3) modifies the tm struct. */
285 tmp = *t;
286 s = mktime(&tmp);
287 for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10)
288 *p-- = s % 10 + '0';
289 return(_add(++p));
290}
291
292static
293_conv(n, digits, pad)
294 int n, digits;
295 char pad;
296{
297 static char buf[10];
298 register char *p;
299
300 for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
301 *p-- = n % 10 + '0';
302 while (p > buf && digits-- > 0)
303 *p-- = pad;
304 return(_add(++p));
305}
306
307static
308_add(str)
309 register char *str;
310{
311 for (;; ++pt, --gsize) {
312 if (!gsize)
313 return(0);
314 if (!(*pt = *str++))
315 return(1);
316 }
317}