xref: /csrg-svn/lib/libc/string/strftime.c (revision 37346)
137103Sbostic /*
237103Sbostic  * Copyright (c) 1989 The Regents of the University of California.
337103Sbostic  * All rights reserved.
437103Sbostic  *
537103Sbostic  * Redistribution and use in source and binary forms are permitted
637103Sbostic  * provided that the above copyright notice and this paragraph are
737103Sbostic  * duplicated in all such forms and that any documentation,
837103Sbostic  * advertising materials, and other materials related to such
937103Sbostic  * distribution and use acknowledge that the software was developed
1037103Sbostic  * by the University of California, Berkeley.  The name of the
1137103Sbostic  * University may not be used to endorse or promote products derived
1237103Sbostic  * from this software without specific prior written permission.
1337103Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437103Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537103Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637103Sbostic  */
1737103Sbostic 
1837103Sbostic #if defined(LIBC_SCCS) && !defined(lint)
19*37346Sbostic static char sccsid[] = "@(#)strftime.c	5.6 (Berkeley) 04/09/89";
2037103Sbostic #endif /* LIBC_SCCS and not lint */
2137103Sbostic 
2237103Sbostic #include <sys/types.h>
2337103Sbostic #include <sys/time.h>
2437103Sbostic #include <tzfile.h>
2537103Sbostic 
2637103Sbostic static char *afmt[] = {
2737103Sbostic 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
2837103Sbostic };
2937103Sbostic static char *Afmt[] = {
3037103Sbostic 	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
3137103Sbostic 	"Saturday",
3237103Sbostic };
3337103Sbostic static char *bfmt[] = {
3437103Sbostic 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
3537103Sbostic 	"Oct", "Nov", "Dec",
3637103Sbostic };
3737103Sbostic static char *Bfmt[] = {
3837103Sbostic 	"January", "February", "March", "April", "May", "June", "July",
3937103Sbostic 	"August", "September", "October", "November", "December",
4037103Sbostic };
4137103Sbostic 
4237103Sbostic static size_t gsize;
4337103Sbostic static char *pt;
4437103Sbostic 
4537103Sbostic size_t
4637103Sbostic strftime(s, maxsize, format, t)
4737103Sbostic 	char *s;
4837103Sbostic 	char *format;
4937103Sbostic 	size_t maxsize;
5037103Sbostic 	struct tm *t;
5137103Sbostic {
5237103Sbostic 	size_t _fmt();
5337103Sbostic 
5437103Sbostic 	pt = s;
5537103Sbostic 	if ((gsize = maxsize) < 1)
5637103Sbostic 		return(0);
5737103Sbostic 	if (_fmt(format, t)) {
5837103Sbostic 		*pt = '\0';
5937103Sbostic 		return(maxsize - gsize);
6037103Sbostic 	}
6137103Sbostic 	return(0);
6237103Sbostic }
6337103Sbostic 
6437103Sbostic static size_t
6537103Sbostic _fmt(format, t)
6637103Sbostic 	register char *format;
6737103Sbostic 	struct tm *t;
6837103Sbostic {
6937103Sbostic 	for (; *format; ++format) {
7037103Sbostic 		if (*format == '%')
7137103Sbostic 			switch(*++format) {
7237176Sbostic 			case '\0':
7337176Sbostic 				--format;
7437176Sbostic 				break;
7537103Sbostic 			case 'A':
7637176Sbostic 				if (t->tm_wday < 0 || t->tm_wday > 6)
7737103Sbostic 					return(0);
7837176Sbostic 				if (!_add(Afmt[t->tm_wday]))
7937176Sbostic 					return(0);
8037103Sbostic 				continue;
8137103Sbostic 			case 'a':
8237176Sbostic 				if (t->tm_wday < 0 || t->tm_wday > 6)
8337103Sbostic 					return(0);
8437176Sbostic 				if (!_add(afmt[t->tm_wday]))
8537176Sbostic 					return(0);
8637103Sbostic 				continue;
8737103Sbostic 			case 'B':
8837176Sbostic 				if (t->tm_mon < 0 || t->tm_mon > 11)
8937176Sbostic 					return(0);
9037103Sbostic 				if (!_add(Bfmt[t->tm_mon]))
9137103Sbostic 					return(0);
9237103Sbostic 				continue;
9337103Sbostic 			case 'b':
9437137Sbostic 			case 'h':
9537176Sbostic 				if (t->tm_mon < 0 || t->tm_mon > 11)
9637176Sbostic 					return(0);
9737103Sbostic 				if (!_add(bfmt[t->tm_mon]))
9837103Sbostic 					return(0);
9937103Sbostic 				continue;
100*37346Sbostic 			case 'C':
101*37346Sbostic 				if (!_fmt("%a %b %e %H:%M:%S %Y", t))
102*37346Sbostic 					return(0);
103*37346Sbostic 				continue;
10437103Sbostic 			case 'c':
10537344Sbostic 				if (!_fmt("%m/%d/%y %H:%M:%S", t))
10637103Sbostic 					return(0);
10737103Sbostic 				continue;
108*37346Sbostic 			case 'e':
109*37346Sbostic 				if (!_conv(t->tm_mday, 2, ' '))
110*37346Sbostic 					return(0);
111*37346Sbostic 				continue;
11237137Sbostic 			case 'D':
11337137Sbostic 				if (!_fmt("%m/%d/%y", t))
11437137Sbostic 					return(0);
11537137Sbostic 				continue;
11637103Sbostic 			case 'd':
117*37346Sbostic 				if (!_conv(t->tm_mday, 2, '0'))
11837103Sbostic 					return(0);
11937103Sbostic 				continue;
12037103Sbostic 			case 'H':
121*37346Sbostic 				if (!_conv(t->tm_hour, 2, '0'))
12237103Sbostic 					return(0);
12337103Sbostic 				continue;
12437103Sbostic 			case 'I':
12537176Sbostic 				if (!_conv(t->tm_hour % 12 ?
126*37346Sbostic 				    t->tm_hour % 12 : 12, 2, '0'))
12737103Sbostic 					return(0);
12837103Sbostic 				continue;
12937103Sbostic 			case 'j':
130*37346Sbostic 				if (!_conv(t->tm_yday + 1, 3, '0'))
13137103Sbostic 					return(0);
13237103Sbostic 				continue;
133*37346Sbostic 			case 'k':
134*37346Sbostic 				if (!_conv(t->tm_hour, 2, ' '))
135*37346Sbostic 					return(0);
136*37346Sbostic 				continue;
137*37346Sbostic 			case 'l':
138*37346Sbostic 				if (!_conv(t->tm_hour % 12 ?
139*37346Sbostic 				    t->tm_hour % 12 : 12, 2, ' '))
140*37346Sbostic 					return(0);
141*37346Sbostic 				continue;
14237103Sbostic 			case 'M':
143*37346Sbostic 				if (!_conv(t->tm_min, 2, '0'))
14437103Sbostic 					return(0);
14537103Sbostic 				continue;
14637103Sbostic 			case 'm':
147*37346Sbostic 				if (!_conv(t->tm_mon + 1, 2, '0'))
14837103Sbostic 					return(0);
14937103Sbostic 				continue;
15037137Sbostic 			case 'n':
15137137Sbostic 				if (!_add("\n"))
15237137Sbostic 					return(0);
15337137Sbostic 				continue;
15437103Sbostic 			case 'p':
15537176Sbostic 				if (!_add(t->tm_hour >= 12 ? "PM" : "AM"))
15637103Sbostic 					return(0);
15737103Sbostic 				continue;
15837137Sbostic 			case 'R':
15937137Sbostic 				if (!_fmt("%H:%M", t))
16037137Sbostic 					return(0);
16137137Sbostic 				continue;
16237137Sbostic 			case 'r':
16337137Sbostic 				if (!_fmt("%I:%M:%S %p", t))
16437137Sbostic 					return(0);
16537137Sbostic 				continue;
16637103Sbostic 			case 'S':
167*37346Sbostic 				if (!_conv(t->tm_sec, 2, '0'))
16837103Sbostic 					return(0);
16937103Sbostic 				continue;
17037137Sbostic 			case 'T':
17137137Sbostic 			case 'X':
17237137Sbostic 				if (!_fmt("%H:%M:%S", t))
17337137Sbostic 					return(0);
17437137Sbostic 				continue;
17537137Sbostic 			case 't':
17637137Sbostic 				if (!_add("\t"))
17737137Sbostic 					return(0);
17837137Sbostic 				continue;
17937103Sbostic 			case 'U':
18037103Sbostic 				if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
181*37346Sbostic 				    2, '0'))
18237103Sbostic 					return(0);
18337103Sbostic 				continue;
18437103Sbostic 			case 'W':
18537103Sbostic 				if (!_conv((t->tm_yday + 7 -
18637176Sbostic 				    (t->tm_wday ? (t->tm_wday - 1) : 6))
187*37346Sbostic 				    / 7, 2, '0'))
18837103Sbostic 					return(0);
18937103Sbostic 				continue;
19037103Sbostic 			case 'w':
191*37346Sbostic 				if (!_conv(t->tm_wday, 1, '0'))
19237103Sbostic 					return(0);
19337103Sbostic 				continue;
19437103Sbostic 			case 'x':
19537344Sbostic 				if (!_fmt("%m/%d/%y", t))
19637103Sbostic 					return(0);
19737103Sbostic 				continue;
19837103Sbostic 			case 'y':
19937103Sbostic 				if (!_conv((t->tm_year + TM_YEAR_BASE)
200*37346Sbostic 				    % 100, 2, '0'))
20137103Sbostic 					return(0);
20237103Sbostic 				continue;
20337103Sbostic 			case 'Y':
204*37346Sbostic 				if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0'))
20537103Sbostic 					return(0);
20637103Sbostic 				continue;
20737103Sbostic 			case 'Z':
20837176Sbostic 				if (!t->tm_zone || !_add(t->tm_zone))
20937103Sbostic 					return(0);
21037103Sbostic 				continue;
21137103Sbostic 			case '%':
21237103Sbostic 			/*
21337103Sbostic 			 * X311J/88-090 (4.12.3.5): if conversion char is
21437103Sbostic 			 * undefined, behavior is undefined.  Print out the
215*37346Sbostic 			 * character itself as printf(3) does.
21637103Sbostic 			 */
21737103Sbostic 			default:
21837103Sbostic 				break;
21937103Sbostic 		}
22037103Sbostic 		if (!gsize--)
22137103Sbostic 			return(0);
22237103Sbostic 		*pt++ = *format;
22337103Sbostic 	}
22437103Sbostic 	return(gsize);
22537103Sbostic }
22637103Sbostic 
22737103Sbostic static
228*37346Sbostic _conv(n, digits, pad)
22937103Sbostic 	int n, digits;
230*37346Sbostic 	char pad;
23137103Sbostic {
23237103Sbostic 	static char buf[10];
23337103Sbostic 	register char *p;
23437103Sbostic 
23537103Sbostic 	for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
23637103Sbostic 		*p-- = n % 10 + '0';
23737103Sbostic 	while (p > buf && digits-- > 0)
238*37346Sbostic 		*p-- = pad;
23937103Sbostic 	return(_add(++p));
24037103Sbostic }
24137103Sbostic 
24237103Sbostic static
24337103Sbostic _add(str)
24437103Sbostic 	register char *str;
24537103Sbostic {
24637103Sbostic 	for (;; ++pt, --gsize) {
24737103Sbostic 		if (!gsize)
24837103Sbostic 			return(0);
24937103Sbostic 		if (!(*pt = *str++))
25037103Sbostic 			return(1);
25137103Sbostic 	}
25237103Sbostic }
253