Annotation of embedaddon/trafshow/strftime.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (c) 1989, 1993
3: * The Regents of the University of California. 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[] = "@(#)strftime.c 8.1 (Berkeley) 6/4/93";
36: #endif /* LIBC_SCCS and not lint */
37:
38: #include <sys/types.h>
39: #include <sys/time.h>
40: #include <tzfile.h>
41: #include <limits.h>
42: #include <stdio.h>
43:
44: /*
45: ** 302 / 1000 is log10(2.0) rounded up.
46: ** Subtract one for the sign bit;
47: ** add one for integer division truncation;
48: ** add one more for a minus sign.
49: */
50: #define INT_STRLEN_MAXIMUM(type) \
51: ((sizeof(type) * CHAR_BIT - 1) * 302 / 1000 + 2)
52:
53: /*
54: ** Based on elsieid[] = "@(#)strftime.c 7.15"
55: **
56: ** This is ANSIish only when time is treated identically in all locales and
57: ** when "multibyte character == plain character".
58: */
59:
60: static const char afmt[][4] = {
61: "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
62: };
63: static const char Afmt[][10] = {
64: "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
65: "Saturday"
66: };
67: static const char bfmt[][4] = {
68: "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
69: "Oct", "Nov", "Dec"
70: };
71: static const char Bfmt[][10] = {
72: "January", "February", "March", "April", "May", "June", "July",
73: "August", "September", "October", "November", "December"
74: };
75:
76: static char *_add __P((const char *, char *, const char *));
77: static char *_conv __P((int, const char *, char *, const char *));
78: static char *_secs __P((const struct tm *, char *, const char *));
79: static char *_fmt __P((const char *, const struct tm *, char *, const char *));
80:
81: extern char *tzname[];
82:
83: size_t
84: strftime(s, maxsize, format, t)
85: char *s;
86: size_t maxsize;
87: const char *format;
88: const struct tm *t;
89: {
90: char *p;
91:
92: p = _fmt(format, t, s, s + maxsize);
93: if (p == s + maxsize)
94: return (0);
95: *p = '\0';
96: return (p - s);
97: }
98:
99: static char *
100: _fmt(format, t, pt, ptlim)
101: const char *format;
102: const struct tm *t;
103: char *pt;
104: const char *ptlim;
105: {
106: for (; *format; ++format) {
107: if (*format == '%') {
108: label:
109: switch(*++format) {
110: case '\0':
111: --format;
112: break;
113: case 'A':
114: pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
115: "?" : Afmt[t->tm_wday], pt, ptlim);
116: continue;
117: case 'a':
118: pt = _add((t->tm_wday < 0 || t->tm_wday > 6) ?
119: "?" : afmt[t->tm_wday], pt, ptlim);
120: continue;
121: case 'B':
122: pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
123: "?" : Bfmt[t->tm_mon], pt, ptlim);
124: continue;
125: case 'b':
126: case 'h':
127: pt = _add((t->tm_mon < 0 || t->tm_mon > 11) ?
128: "?" : bfmt[t->tm_mon], pt, ptlim);
129: continue;
130: case 'c':
131: pt = _fmt("%D %X", t, pt, ptlim);
132: continue;
133: case 'C':
134: /*
135: ** %C used to do a...
136: ** _fmt("%a %b %e %X %Y", t);
137: ** ...whereas now POSIX 1003.2 calls for
138: ** something completely different.
139: ** (ado, 5/24/93)
140: */
141: pt = _conv((t->tm_year + TM_YEAR_BASE) / 100,
142: "%02d", pt, ptlim);
143: continue;
144: case 'D':
145: pt = _fmt("%m/%d/%y", t, pt, ptlim);
146: continue;
147: case 'x':
148: /*
149: ** Version 3.0 of strftime from Arnold Robbins
150: ** (arnold@skeeve.atl.ga.us) does the
151: ** equivalent of...
152: ** _fmt("%a %b %e %Y");
153: ** ...for %x; since the X3J11 C language
154: ** standard calls for "date, using locale's
155: ** date format," anything goes. Using just
156: ** numbers (as here) makes Quakers happier.
157: ** Word from Paul Eggert (eggert@twinsun.com)
158: ** is that %Y-%m-%d is the ISO standard date
159: ** format, specified in ISO 2014 and later
160: ** ISO 8601:1988, with a summary available in
161: ** pub/doc/ISO/english/ISO8601.ps.Z on
162: ** ftp.uni-erlangen.de.
163: ** (ado, 5/30/93)
164: */
165: pt = _fmt("%m/%d/%y", t, pt, ptlim);
166: continue;
167: case 'd':
168: pt = _conv(t->tm_mday, "%02d", pt, ptlim);
169: continue;
170: case 'E':
171: case 'O':
172: /*
173: ** POSIX locale extensions, a la
174: ** Arnold Robbins' strftime version 3.0.
175: ** The sequences
176: ** %Ec %EC %Ex %Ey %EY
177: ** %Od %oe %OH %OI %Om %OM
178: ** %OS %Ou %OU %OV %Ow %OW %Oy
179: ** are supposed to provide alternate
180: ** representations.
181: ** (ado, 5/24/93)
182: */
183: goto label;
184: case 'e':
185: pt = _conv(t->tm_mday, "%2d", pt, ptlim);
186: continue;
187: case 'H':
188: pt = _conv(t->tm_hour, "%02d", pt, ptlim);
189: continue;
190: case 'I':
191: pt = _conv((t->tm_hour % 12) ?
192: (t->tm_hour % 12) : 12,
193: "%02d", pt, ptlim);
194: continue;
195: case 'j':
196: pt = _conv(t->tm_yday + 1, "%03d", pt, ptlim);
197: continue;
198: case 'k':
199: /*
200: ** This used to be...
201: ** _conv(t->tm_hour % 12 ?
202: ** t->tm_hour % 12 : 12, 2, ' ');
203: ** ...and has been changed to the below to
204: ** match SunOS 4.1.1 and Arnold Robbins'
205: ** strftime version 3.0. That is, "%k" and
206: ** "%l" have been swapped.
207: ** (ado, 5/24/93)
208: */
209: pt = _conv(t->tm_hour, "%2d", pt, ptlim);
210: continue;
211: #ifdef KITCHEN_SINK
212: case 'K':
213: /*
214: ** After all this time, still unclaimed!
215: */
216: pt = _add("kitchen sink", pt, ptlim);
217: continue;
218: #endif /* defined KITCHEN_SINK */
219: case 'l':
220: /*
221: ** This used to be...
222: ** _conv(t->tm_hour, 2, ' ');
223: ** ...and has been changed to the below to
224: ** match SunOS 4.1.1 and Arnold Robbin's
225: ** strftime version 3.0. That is, "%k" and
226: ** "%l" have been swapped.
227: ** (ado, 5/24/93)
228: */
229: pt = _conv((t->tm_hour % 12) ?
230: (t->tm_hour % 12) : 12,
231: "%2d", pt, ptlim);
232: continue;
233: case 'M':
234: pt = _conv(t->tm_min, "%02d", pt, ptlim);
235: continue;
236: case 'm':
237: pt = _conv(t->tm_mon + 1, "%02d", pt, ptlim);
238: continue;
239: case 'n':
240: pt = _add("\n", pt, ptlim);
241: continue;
242: case 'p':
243: pt = _add(t->tm_hour >= 12 ? "PM" : "AM",
244: pt, ptlim);
245: continue;
246: case 'R':
247: pt = _fmt("%H:%M", t, pt, ptlim);
248: continue;
249: case 'r':
250: pt = _fmt("%I:%M:%S %p", t, pt, ptlim);
251: continue;
252: case 'S':
253: pt = _conv(t->tm_sec, "%02d", pt, ptlim);
254: continue;
255: case 's':
256: pt = _secs(t, pt, ptlim);
257: continue;
258: case 'T':
259: case 'X':
260: pt = _fmt("%H:%M:%S", t, pt, ptlim);
261: continue;
262: case 't':
263: pt = _add("\t", pt, ptlim);
264: continue;
265: case 'U':
266: pt = _conv((t->tm_yday + 7 - t->tm_wday) / 7,
267: "%02d", pt, ptlim);
268: continue;
269: case 'u':
270: /*
271: ** From Arnold Robbins' strftime version 3.0:
272: ** "ISO 8601: Weekday as a decimal number
273: ** [1 (Monday) - 7]"
274: ** (ado, 5/24/93)
275: */
276: pt = _conv((t->tm_wday == 0) ? 7 : t->tm_wday,
277: "%d", pt, ptlim);
278: continue;
279: case 'V':
280: /*
281: ** From Arnold Robbins' strftime version 3.0:
282: ** "the week number of the year (the first
283: ** Monday as the first day of week 1) as a
284: ** decimal number (01-53). The method for
285: ** determining the week number is as specified
286: ** by ISO 8601 (to wit: if the week containing
287: ** January 1 has four or more days in the new
288: ** year, then it is week 1, otherwise it is
289: ** week 53 of the previous year and the next
290: ** week is week 1)."
291: ** (ado, 5/24/93)
292: */
293: /*
294: ** XXX--If January 1 falls on a Friday,
295: ** January 1-3 are part of week 53 of the
296: ** previous year. By analogy, if January
297: ** 1 falls on a Thursday, are December 29-31
298: ** of the PREVIOUS year part of week 1???
299: ** (ado 5/24/93)
300: **
301: ** You are understood not to expect this.
302: */
303: {
304: int i;
305:
306: i = (t->tm_yday + 10 - (t->tm_wday ?
307: (t->tm_wday - 1) : 6)) / 7;
308: pt = _conv((i == 0) ? 53 : i,
309: "%02d", pt, ptlim);
310: }
311: continue;
312: #ifdef notdef
313: /* Not in POSIX date(1), System V or ANSI C. */
314: case 'v':
315: /*
316: ** From Arnold Robbins' strftime version 3.0:
317: ** "date as dd-bbb-YYYY"
318: ** (ado, 5/24/93)
319: */
320: pt = _fmt("%e-%b-%Y", t, pt, ptlim);
321: continue;
322: #endif
323: case 'W':
324: pt = _conv((t->tm_yday + 7 -
325: (t->tm_wday ?
326: (t->tm_wday - 1) : 6)) / 7,
327: "%02d", pt, ptlim);
328: continue;
329: case 'w':
330: pt = _conv(t->tm_wday, "%d", pt, ptlim);
331: continue;
332: case 'y':
333: pt = _conv((t->tm_year + TM_YEAR_BASE) % 100,
334: "%02d", pt, ptlim);
335: continue;
336: case 'Y':
337: pt = _conv(t->tm_year + TM_YEAR_BASE, "%04d",
338: pt, ptlim);
339: continue;
340: case 'Z':
341: #ifdef TM_ZONE
342: if (t->TM_ZONE)
343: pt = _add(t->TM_ZONE, pt, ptlim);
344: else
345: #endif /* defined TM_ZONE */
346: if (t->tm_isdst == 0 || t->tm_isdst == 1) {
347: pt = _add(tzname[t->tm_isdst],
348: pt, ptlim);
349: } else pt = _add("?", pt, ptlim);
350: continue;
351: case '%':
352: /*
353: * X311J/88-090 (4.12.3.5): if conversion char is
354: * undefined, behavior is undefined. Print out the
355: * character itself as printf(3) does.
356: */
357: default:
358: break;
359: }
360: }
361: if (pt == ptlim)
362: break;
363: *pt++ = *format;
364: }
365: return (pt);
366: }
367:
368: static char *
369: _secs(t, pt, ptlim)
370: const struct tm *t;
371: char *pt;
372: const char *ptlim;
373: {
374: struct tm tmp;
375: time_t s;
376:
377: tmp = *t;
378: s = mktime(&tmp);
379: return (_conv((int)s, "%d", pt, ptlim));
380: }
381:
382: static char *
383: _conv(n, format, pt, ptlim)
384: int n;
385: const char *format;
386: char *pt;
387: const char *ptlim;
388: {
389: char buf[INT_STRLEN_MAXIMUM(int) + 1];
390:
391: (void) sprintf(buf, format, n);
392: return (_add(buf, pt, ptlim));
393: }
394:
395: static char *
396: _add(str, pt, ptlim)
397: const char *str;
398: char *pt;
399: const char *ptlim;
400: {
401:
402: while (pt < ptlim && (*pt = *str++) != '\0')
403: ++pt;
404: return (pt);
405: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>