xref: /csrg-svn/lib/libc/string/strftime.c (revision 37103)
1*37103Sbostic /*
2*37103Sbostic  * Copyright (c) 1989 The Regents of the University of California.
3*37103Sbostic  * All rights reserved.
4*37103Sbostic  *
5*37103Sbostic  * Redistribution and use in source and binary forms are permitted
6*37103Sbostic  * provided that the above copyright notice and this paragraph are
7*37103Sbostic  * duplicated in all such forms and that any documentation,
8*37103Sbostic  * advertising materials, and other materials related to such
9*37103Sbostic  * distribution and use acknowledge that the software was developed
10*37103Sbostic  * by the University of California, Berkeley.  The name of the
11*37103Sbostic  * University may not be used to endorse or promote products derived
12*37103Sbostic  * from this software without specific prior written permission.
13*37103Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*37103Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*37103Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16*37103Sbostic  */
17*37103Sbostic 
18*37103Sbostic #if defined(LIBC_SCCS) && !defined(lint)
19*37103Sbostic static char sccsid[] = "@(#)strftime.c	5.1 (Berkeley) 03/08/89";
20*37103Sbostic #endif /* LIBC_SCCS and not lint */
21*37103Sbostic 
22*37103Sbostic #include <sys/types.h>
23*37103Sbostic #include <sys/time.h>
24*37103Sbostic #include <tzfile.h>
25*37103Sbostic 
26*37103Sbostic static char *afmt[] = {
27*37103Sbostic 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
28*37103Sbostic };
29*37103Sbostic static char *Afmt[] = {
30*37103Sbostic 	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
31*37103Sbostic 	"Saturday",
32*37103Sbostic };
33*37103Sbostic static char *bfmt[] = {
34*37103Sbostic 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
35*37103Sbostic 	"Oct", "Nov", "Dec",
36*37103Sbostic };
37*37103Sbostic static char *Bfmt[] = {
38*37103Sbostic 	"January", "February", "March", "April", "May", "June", "July",
39*37103Sbostic 	"August", "September", "October", "November", "December",
40*37103Sbostic };
41*37103Sbostic 
42*37103Sbostic static size_t gsize;
43*37103Sbostic static char *pt;
44*37103Sbostic 
45*37103Sbostic size_t
46*37103Sbostic strftime(s, maxsize, format, t)
47*37103Sbostic 	char *s;
48*37103Sbostic 	char *format;
49*37103Sbostic 	size_t maxsize;
50*37103Sbostic 	struct tm *t;
51*37103Sbostic {
52*37103Sbostic 	size_t _fmt();
53*37103Sbostic 
54*37103Sbostic 	pt = s;
55*37103Sbostic 	if ((gsize = maxsize) < 1)
56*37103Sbostic 		return(0);
57*37103Sbostic 	if (_fmt(format, t)) {
58*37103Sbostic 		*pt = '\0';
59*37103Sbostic 		return(maxsize - gsize);
60*37103Sbostic 	}
61*37103Sbostic 	return(0);
62*37103Sbostic }
63*37103Sbostic 
64*37103Sbostic static size_t
65*37103Sbostic _fmt(format, t)
66*37103Sbostic 	register char *format;
67*37103Sbostic 	struct tm *t;
68*37103Sbostic {
69*37103Sbostic 	char *timezone();
70*37103Sbostic 
71*37103Sbostic 	for (; *format; ++format) {
72*37103Sbostic 		if (*format == '%')
73*37103Sbostic 			switch(*++format) {
74*37103Sbostic 			case 'A':
75*37103Sbostic 				if (!_add(Afmt[t->tm_mon]))
76*37103Sbostic 					return(0);
77*37103Sbostic 				continue;
78*37103Sbostic 			case 'a':
79*37103Sbostic 				if (!_add(afmt[t->tm_mon]))
80*37103Sbostic 					return(0);
81*37103Sbostic 				continue;
82*37103Sbostic 			case 'B':
83*37103Sbostic 				if (!_add(Bfmt[t->tm_mon]))
84*37103Sbostic 					return(0);
85*37103Sbostic 				continue;
86*37103Sbostic 			case 'b':
87*37103Sbostic 				if (!_add(bfmt[t->tm_mon]))
88*37103Sbostic 					return(0);
89*37103Sbostic 				continue;
90*37103Sbostic 			case 'c':
91*37103Sbostic 				if (!_fmt("%x %X %Z %Y", t))
92*37103Sbostic 					return(0);
93*37103Sbostic 				continue;
94*37103Sbostic 			case 'd':
95*37103Sbostic 				if (!_conv(t->tm_mday, 2))
96*37103Sbostic 					return(0);
97*37103Sbostic 				continue;
98*37103Sbostic 			case 'H':
99*37103Sbostic 				if (!_conv(t->tm_hour, 2))
100*37103Sbostic 					return(0);
101*37103Sbostic 				continue;
102*37103Sbostic 			case 'I':
103*37103Sbostic 				if (!_conv((t->tm_hour - 1) % 12 + 1, 2))
104*37103Sbostic 					return(0);
105*37103Sbostic 				continue;
106*37103Sbostic 			case 'j':
107*37103Sbostic 				if (!_conv(t->tm_yday + 1, 3))
108*37103Sbostic 					return(0);
109*37103Sbostic 				continue;
110*37103Sbostic 			case 'M':
111*37103Sbostic 				if (!_conv(t->tm_min, 2))
112*37103Sbostic 					return(0);
113*37103Sbostic 				continue;
114*37103Sbostic 			case 'm':
115*37103Sbostic 				if (!_conv(t->tm_mon + 1, 2))
116*37103Sbostic 					return(0);
117*37103Sbostic 				continue;
118*37103Sbostic 			case 'p':
119*37103Sbostic 				if (!_add(t->tm_hour >= 12 ? "AM" : "PM"))
120*37103Sbostic 					return(0);
121*37103Sbostic 				continue;
122*37103Sbostic 			case 'S':
123*37103Sbostic 				if (!_conv(t->tm_sec, 2))
124*37103Sbostic 					return(0);
125*37103Sbostic 				continue;
126*37103Sbostic 			case 'U':
127*37103Sbostic 				if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
128*37103Sbostic 				    2))
129*37103Sbostic 					return(0);
130*37103Sbostic 				continue;
131*37103Sbostic 			case 'W':
132*37103Sbostic 				if (!_conv((t->tm_yday + 7 -
133*37103Sbostic 				    (t->tm_wday ? t->tm_wday : 6)) / 7, 2))
134*37103Sbostic 					return(0);
135*37103Sbostic 				continue;
136*37103Sbostic 			case 'w':
137*37103Sbostic 				if (!_conv(t->tm_wday, 1))
138*37103Sbostic 					return(0);
139*37103Sbostic 				continue;
140*37103Sbostic 			case 'X':
141*37103Sbostic 				if (!_fmt("%H:%M:%S", t))
142*37103Sbostic 					return(0);
143*37103Sbostic 				continue;
144*37103Sbostic 			case 'x':
145*37103Sbostic 				if (!_fmt("%a %b %d", t))
146*37103Sbostic 					return(0);
147*37103Sbostic 				continue;
148*37103Sbostic 			case 'y':
149*37103Sbostic 				if (!_conv((t->tm_year + TM_YEAR_BASE)
150*37103Sbostic 				    % 100, 2))
151*37103Sbostic 					return(0);
152*37103Sbostic 				continue;
153*37103Sbostic 			case 'Y':
154*37103Sbostic 				if (!_conv(t->tm_year + TM_YEAR_BASE, 4))
155*37103Sbostic 					return(0);
156*37103Sbostic 				continue;
157*37103Sbostic 			case 'Z':
158*37103Sbostic 				if (!_add(t->tm_zone))
159*37103Sbostic 					return(0);
160*37103Sbostic 				continue;
161*37103Sbostic 			case '%':
162*37103Sbostic 			/*
163*37103Sbostic 			 * X311J/88-090 (4.12.3.5): if conversion char is
164*37103Sbostic 			 * undefined, behavior is undefined.  Print out the
165*37103Sbostic 			 * character itself as printf(3) also does.
166*37103Sbostic 			 */
167*37103Sbostic 			default:
168*37103Sbostic 				break;
169*37103Sbostic 		}
170*37103Sbostic 		if (!gsize--)
171*37103Sbostic 			return(0);
172*37103Sbostic 		*pt++ = *format;
173*37103Sbostic 	}
174*37103Sbostic 	return(gsize);
175*37103Sbostic }
176*37103Sbostic 
177*37103Sbostic static
178*37103Sbostic _conv(n, digits)
179*37103Sbostic 	int n, digits;
180*37103Sbostic {
181*37103Sbostic 	static char buf[10];
182*37103Sbostic 	register char *p;
183*37103Sbostic 
184*37103Sbostic 	for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
185*37103Sbostic 		*p-- = n % 10 + '0';
186*37103Sbostic 	while (p > buf && digits-- > 0)
187*37103Sbostic 		*p-- = '0';
188*37103Sbostic 	return(_add(++p));
189*37103Sbostic }
190*37103Sbostic 
191*37103Sbostic static
192*37103Sbostic _add(str)
193*37103Sbostic 	register char *str;
194*37103Sbostic {
195*37103Sbostic 	for (;; ++pt, --gsize) {
196*37103Sbostic 		if (!gsize)
197*37103Sbostic 			return(0);
198*37103Sbostic 		if (!(*pt = *str++))
199*37103Sbostic 			return(1);
200*37103Sbostic 	}
201*37103Sbostic }
202