xref: /csrg-svn/lib/libc/string/strftime.c (revision 46613)
137103Sbostic /*
237103Sbostic  * Copyright (c) 1989 The Regents of the University of California.
337103Sbostic  * All rights reserved.
437103Sbostic  *
542636Sbostic  * %sccs.include.redist.c%
637103Sbostic  */
737103Sbostic 
837103Sbostic #if defined(LIBC_SCCS) && !defined(lint)
9*46613Sbostic static char sccsid[] = "@(#)strftime.c	5.11 (Berkeley) 02/24/91";
1037103Sbostic #endif /* LIBC_SCCS and not lint */
1137103Sbostic 
1237103Sbostic #include <sys/types.h>
1337103Sbostic #include <sys/time.h>
1437103Sbostic #include <tzfile.h>
1542181Sbostic #include <string.h>
1637103Sbostic 
1737103Sbostic static char *afmt[] = {
1837103Sbostic 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
1937103Sbostic };
2037103Sbostic static char *Afmt[] = {
2137103Sbostic 	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
2237103Sbostic 	"Saturday",
2337103Sbostic };
2437103Sbostic static char *bfmt[] = {
2537103Sbostic 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
2637103Sbostic 	"Oct", "Nov", "Dec",
2737103Sbostic };
2837103Sbostic static char *Bfmt[] = {
2937103Sbostic 	"January", "February", "March", "April", "May", "June", "July",
3037103Sbostic 	"August", "September", "October", "November", "December",
3137103Sbostic };
3237103Sbostic 
3337103Sbostic static size_t gsize;
3437103Sbostic static char *pt;
35*46613Sbostic static int _add(), _conv(), _secs();
3637103Sbostic 
3737103Sbostic size_t
3837103Sbostic strftime(s, maxsize, format, t)
3937103Sbostic 	char *s;
4037103Sbostic 	size_t maxsize;
41*46613Sbostic 	const char *format;
42*46613Sbostic 	const struct tm *t;
4337103Sbostic {
44*46613Sbostic 	static size_t _fmt();
4537103Sbostic 
4637103Sbostic 	pt = s;
4737103Sbostic 	if ((gsize = maxsize) < 1)
4837103Sbostic 		return(0);
4937103Sbostic 	if (_fmt(format, t)) {
5037103Sbostic 		*pt = '\0';
5137103Sbostic 		return(maxsize - gsize);
5237103Sbostic 	}
5337103Sbostic 	return(0);
5437103Sbostic }
5537103Sbostic 
5637103Sbostic static size_t
5737103Sbostic _fmt(format, t)
5837103Sbostic 	register char *format;
5937103Sbostic 	struct tm *t;
6037103Sbostic {
6137103Sbostic 	for (; *format; ++format) {
6237103Sbostic 		if (*format == '%')
6337103Sbostic 			switch(*++format) {
6437176Sbostic 			case '\0':
6537176Sbostic 				--format;
6637176Sbostic 				break;
6737103Sbostic 			case 'A':
6837176Sbostic 				if (t->tm_wday < 0 || t->tm_wday > 6)
6937103Sbostic 					return(0);
7037176Sbostic 				if (!_add(Afmt[t->tm_wday]))
7137176Sbostic 					return(0);
7237103Sbostic 				continue;
7337103Sbostic 			case 'a':
7437176Sbostic 				if (t->tm_wday < 0 || t->tm_wday > 6)
7537103Sbostic 					return(0);
7637176Sbostic 				if (!_add(afmt[t->tm_wday]))
7737176Sbostic 					return(0);
7837103Sbostic 				continue;
7937103Sbostic 			case 'B':
8037176Sbostic 				if (t->tm_mon < 0 || t->tm_mon > 11)
8137176Sbostic 					return(0);
8237103Sbostic 				if (!_add(Bfmt[t->tm_mon]))
8337103Sbostic 					return(0);
8437103Sbostic 				continue;
8537103Sbostic 			case 'b':
8637137Sbostic 			case 'h':
8737176Sbostic 				if (t->tm_mon < 0 || t->tm_mon > 11)
8837176Sbostic 					return(0);
8937103Sbostic 				if (!_add(bfmt[t->tm_mon]))
9037103Sbostic 					return(0);
9137103Sbostic 				continue;
9237346Sbostic 			case 'C':
9337346Sbostic 				if (!_fmt("%a %b %e %H:%M:%S %Y", t))
9437346Sbostic 					return(0);
9537346Sbostic 				continue;
9637103Sbostic 			case 'c':
9737344Sbostic 				if (!_fmt("%m/%d/%y %H:%M:%S", t))
9837103Sbostic 					return(0);
9937103Sbostic 				continue;
10037137Sbostic 			case 'D':
10137137Sbostic 				if (!_fmt("%m/%d/%y", t))
10237137Sbostic 					return(0);
10337137Sbostic 				continue;
10437103Sbostic 			case 'd':
10537346Sbostic 				if (!_conv(t->tm_mday, 2, '0'))
10637103Sbostic 					return(0);
10737103Sbostic 				continue;
10845668Sbostic 			case 'e':
10945668Sbostic 				if (!_conv(t->tm_mday, 2, ' '))
11045668Sbostic 					return(0);
11145668Sbostic 				continue;
11237103Sbostic 			case 'H':
11337346Sbostic 				if (!_conv(t->tm_hour, 2, '0'))
11437103Sbostic 					return(0);
11537103Sbostic 				continue;
11637103Sbostic 			case 'I':
11737176Sbostic 				if (!_conv(t->tm_hour % 12 ?
11837346Sbostic 				    t->tm_hour % 12 : 12, 2, '0'))
11937103Sbostic 					return(0);
12037103Sbostic 				continue;
12137103Sbostic 			case 'j':
12237346Sbostic 				if (!_conv(t->tm_yday + 1, 3, '0'))
12337103Sbostic 					return(0);
12437103Sbostic 				continue;
12537346Sbostic 			case 'k':
12637346Sbostic 				if (!_conv(t->tm_hour, 2, ' '))
12737346Sbostic 					return(0);
12837346Sbostic 				continue;
12937346Sbostic 			case 'l':
13037346Sbostic 				if (!_conv(t->tm_hour % 12 ?
13137346Sbostic 				    t->tm_hour % 12 : 12, 2, ' '))
13237346Sbostic 					return(0);
13337346Sbostic 				continue;
13437103Sbostic 			case 'M':
13537346Sbostic 				if (!_conv(t->tm_min, 2, '0'))
13637103Sbostic 					return(0);
13737103Sbostic 				continue;
13837103Sbostic 			case 'm':
13937346Sbostic 				if (!_conv(t->tm_mon + 1, 2, '0'))
14037103Sbostic 					return(0);
14137103Sbostic 				continue;
14237137Sbostic 			case 'n':
14337137Sbostic 				if (!_add("\n"))
14437137Sbostic 					return(0);
14537137Sbostic 				continue;
14637103Sbostic 			case 'p':
14737176Sbostic 				if (!_add(t->tm_hour >= 12 ? "PM" : "AM"))
14837103Sbostic 					return(0);
14937103Sbostic 				continue;
15037137Sbostic 			case 'R':
15137137Sbostic 				if (!_fmt("%H:%M", t))
15237137Sbostic 					return(0);
15337137Sbostic 				continue;
15437137Sbostic 			case 'r':
15537137Sbostic 				if (!_fmt("%I:%M:%S %p", t))
15637137Sbostic 					return(0);
15737137Sbostic 				continue;
15837103Sbostic 			case 'S':
15937346Sbostic 				if (!_conv(t->tm_sec, 2, '0'))
16037103Sbostic 					return(0);
16137103Sbostic 				continue;
16245668Sbostic 			case 's':
16345668Sbostic 				if (!_secs(t))
16445668Sbostic 					return(0);
16545668Sbostic 				continue;
16637137Sbostic 			case 'T':
16737137Sbostic 			case 'X':
16837137Sbostic 				if (!_fmt("%H:%M:%S", t))
16937137Sbostic 					return(0);
17037137Sbostic 				continue;
17137137Sbostic 			case 't':
17237137Sbostic 				if (!_add("\t"))
17337137Sbostic 					return(0);
17437137Sbostic 				continue;
17537103Sbostic 			case 'U':
17637103Sbostic 				if (!_conv((t->tm_yday + 7 - t->tm_wday) / 7,
17737346Sbostic 				    2, '0'))
17837103Sbostic 					return(0);
17937103Sbostic 				continue;
18037103Sbostic 			case 'W':
18137103Sbostic 				if (!_conv((t->tm_yday + 7 -
18237176Sbostic 				    (t->tm_wday ? (t->tm_wday - 1) : 6))
18337346Sbostic 				    / 7, 2, '0'))
18437103Sbostic 					return(0);
18537103Sbostic 				continue;
18637103Sbostic 			case 'w':
18737346Sbostic 				if (!_conv(t->tm_wday, 1, '0'))
18837103Sbostic 					return(0);
18937103Sbostic 				continue;
19037103Sbostic 			case 'x':
19137344Sbostic 				if (!_fmt("%m/%d/%y", t))
19237103Sbostic 					return(0);
19337103Sbostic 				continue;
19437103Sbostic 			case 'y':
19537103Sbostic 				if (!_conv((t->tm_year + TM_YEAR_BASE)
19637346Sbostic 				    % 100, 2, '0'))
19737103Sbostic 					return(0);
19837103Sbostic 				continue;
19937103Sbostic 			case 'Y':
20037346Sbostic 				if (!_conv(t->tm_year + TM_YEAR_BASE, 4, '0'))
20137103Sbostic 					return(0);
20237103Sbostic 				continue;
20337103Sbostic 			case 'Z':
20437176Sbostic 				if (!t->tm_zone || !_add(t->tm_zone))
20537103Sbostic 					return(0);
20637103Sbostic 				continue;
20737103Sbostic 			case '%':
20837103Sbostic 			/*
20937103Sbostic 			 * X311J/88-090 (4.12.3.5): if conversion char is
21037103Sbostic 			 * undefined, behavior is undefined.  Print out the
21137346Sbostic 			 * character itself as printf(3) does.
21237103Sbostic 			 */
21337103Sbostic 			default:
21437103Sbostic 				break;
21537103Sbostic 		}
21637103Sbostic 		if (!gsize--)
21737103Sbostic 			return(0);
21837103Sbostic 		*pt++ = *format;
21937103Sbostic 	}
22037103Sbostic 	return(gsize);
22137103Sbostic }
22237103Sbostic 
22337103Sbostic static
22445668Sbostic _secs(t)
22545668Sbostic 	struct tm *t;
22645668Sbostic {
22745668Sbostic 	static char buf[15];
22845668Sbostic 	register time_t s;
22945668Sbostic 	register char *p;
23045693Sbostic 	struct tm tmp;
23145668Sbostic 
23245693Sbostic 	/* Make a copy, mktime(3) modifies the tm struct. */
23345693Sbostic 	tmp = *t;
23445693Sbostic 	s = mktime(&tmp);
23545668Sbostic 	for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10)
23645668Sbostic 		*p-- = s % 10 + '0';
23745668Sbostic 	return(_add(++p));
23845668Sbostic }
23945668Sbostic 
24045668Sbostic static
24137346Sbostic _conv(n, digits, pad)
24237103Sbostic 	int n, digits;
24337346Sbostic 	char pad;
24437103Sbostic {
24537103Sbostic 	static char buf[10];
24637103Sbostic 	register char *p;
24737103Sbostic 
24837103Sbostic 	for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits)
24937103Sbostic 		*p-- = n % 10 + '0';
25037103Sbostic 	while (p > buf && digits-- > 0)
25137346Sbostic 		*p-- = pad;
25237103Sbostic 	return(_add(++p));
25337103Sbostic }
25437103Sbostic 
25537103Sbostic static
25637103Sbostic _add(str)
25737103Sbostic 	register char *str;
25837103Sbostic {
25937103Sbostic 	for (;; ++pt, --gsize) {
26037103Sbostic 		if (!gsize)
26137103Sbostic 			return(0);
26237103Sbostic 		if (!(*pt = *str++))
26337103Sbostic 			return(1);
26437103Sbostic 	}
26537103Sbostic }
266