xref: /onnv-gate/usr/src/lib/libast/common/tm/tmxfmt.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * Time_t conversion support
284887Schin  */
294887Schin 
304887Schin #include <tmx.h>
314887Schin #include <ctype.h>
324887Schin 
334887Schin #define warped(t,n)	((t)<((n)-tmxsns(6L*30L*24L*60L*60L,0))||(t)>((n)+tmxsns(24L*60L*60L,0)))
344887Schin 
354887Schin /*
364887Schin  * format n with padding p into s
374887Schin  * return end of s
384887Schin  *
394887Schin  * p:	<0	blank padding
404887Schin  *	 0	no padding
414887Schin  *	>0	0 padding
424887Schin  */
434887Schin 
444887Schin static char*
number(register char * s,register char * e,register long n,register int p,int w,int pad)454887Schin number(register char* s, register char* e, register long n, register int p, int w, int pad)
464887Schin {
474887Schin 	char*	b;
484887Schin 
498462SApril.Chin@Sun.COM 	if (w)
508462SApril.Chin@Sun.COM 	{
518462SApril.Chin@Sun.COM 		if (p > 0 && (pad == 0 || pad == '0'))
528462SApril.Chin@Sun.COM 			while (w > p)
538462SApril.Chin@Sun.COM 			{
548462SApril.Chin@Sun.COM 				p++;
558462SApril.Chin@Sun.COM 				n *= 10;
568462SApril.Chin@Sun.COM 			}
578462SApril.Chin@Sun.COM 		else if (w > p)
588462SApril.Chin@Sun.COM 			p = w;
598462SApril.Chin@Sun.COM 	}
604887Schin 	switch (pad)
614887Schin 	{
624887Schin 	case '-':
634887Schin 		p = 0;
644887Schin 		break;
654887Schin 	case '_':
664887Schin 		if (p > 0)
674887Schin 			p = -p;
684887Schin 		break;
694887Schin 	case '0':
704887Schin 		if (p < 0)
714887Schin 			p = -p;
724887Schin 		break;
734887Schin 	}
744887Schin 	b = s;
754887Schin 	if (p > 0)
764887Schin 		s += sfsprintf(s, e - s, "%0*lu", p, n);
774887Schin 	else if (p < 0)
784887Schin 		s += sfsprintf(s, e - s, "%*lu", -p, n);
794887Schin 	else
804887Schin 		s += sfsprintf(s, e - s, "%lu", n);
814887Schin 	if (w && (s - b) > w)
824887Schin 		*(s = b + w) = 0;
834887Schin 	return s;
844887Schin }
854887Schin 
864887Schin typedef struct Stack_s
874887Schin {
884887Schin 	char*		format;
894887Schin 	int		delimiter;
904887Schin } Stack_t;
914887Schin 
924887Schin /*
934887Schin  * format t into buf of length len
944887Schin  * end of buf is returned
954887Schin  */
964887Schin 
974887Schin char*
tmxfmt(char * buf,size_t len,const char * format,Time_t t)984887Schin tmxfmt(char* buf, size_t len, const char* format, Time_t t)
994887Schin {
1004887Schin 	register char*	cp;
1014887Schin 	register char*	ep;
1024887Schin 	register char*	p;
1034887Schin 	register int	n;
1044887Schin 	int		c;
1054887Schin 	int		i;
1064887Schin 	int		flags;
10710898Sroland.mainz@nrubsig.org 	int		alt;
1084887Schin 	int		pad;
1094887Schin 	int		delimiter;
1104887Schin 	int		width;
1114887Schin 	int		prec;
1124887Schin 	int		parts;
11310898Sroland.mainz@nrubsig.org 	char*		arg;
1144887Schin 	char*		f;
1154887Schin 	const char*	oformat;
11610898Sroland.mainz@nrubsig.org 	Tm_t*		tm;
1174887Schin 	Tm_zone_t*	zp;
1184887Schin 	Time_t		now;
1194887Schin 	Stack_t*	sp;
1204887Schin 	Stack_t		stack[8];
12110898Sroland.mainz@nrubsig.org 	Tm_t		ts;
12210898Sroland.mainz@nrubsig.org 	char		argbuf[256];
1234887Schin 	char		fmt[32];
1244887Schin 
1254887Schin 	tmlocale();
12610898Sroland.mainz@nrubsig.org 	tm = tmxtm(&ts, t, NiL);
1274887Schin 	if (!format || !*format)
1284887Schin 		format = tm_info.deformat;
1294887Schin 	oformat = format;
1304887Schin 	flags = tm_info.flags;
1314887Schin 	sp = &stack[0];
1324887Schin 	cp = buf;
1334887Schin 	ep = buf + len;
1344887Schin 	delimiter = 0;
1354887Schin 	for (;;)
1364887Schin 	{
1374887Schin 		if ((c = *format++) == delimiter)
1384887Schin 		{
1394887Schin 			delimiter = 0;
1404887Schin 			if (sp <= &stack[0])
1414887Schin 				break;
1424887Schin 			sp--;
1434887Schin 			format = sp->format;
1444887Schin 			delimiter = sp->delimiter;
1454887Schin 			continue;
1464887Schin 		}
1474887Schin 		if (c != '%')
1484887Schin 		{
1494887Schin 			if (cp < ep)
1504887Schin 				*cp++ = c;
1514887Schin 			continue;
1524887Schin 		}
15310898Sroland.mainz@nrubsig.org 		alt = 0;
15410898Sroland.mainz@nrubsig.org 		arg = 0;
1554887Schin 		pad = 0;
1564887Schin 		width = 0;
1574887Schin 		prec = 0;
1584887Schin 		parts = 0;
1594887Schin 		for (;;)
1604887Schin 		{
1614887Schin 			switch (c = *format++)
1624887Schin 			{
1634887Schin 			case '_':
1644887Schin 			case '-':
1654887Schin 				pad = c;
1664887Schin 				continue;
1674887Schin 			case 'E':
1684887Schin 			case 'O':
1694887Schin 				if (!isalpha(*format))
1704887Schin 					break;
17110898Sroland.mainz@nrubsig.org 				alt = c;
1724887Schin 				continue;
1734887Schin 			case '0':
1744887Schin 				if (!parts)
1754887Schin 				{
1764887Schin 					pad = c;
1774887Schin 					continue;
1784887Schin 				}
1794887Schin 				/*FALLTHROUGH*/
1804887Schin 			case '1':
1814887Schin 			case '2':
1824887Schin 			case '3':
1834887Schin 			case '4':
1844887Schin 			case '5':
1854887Schin 			case '6':
1864887Schin 			case '7':
1874887Schin 			case '8':
1884887Schin 			case '9':
1894887Schin 				switch (parts)
1904887Schin 				{
1914887Schin 				case 0:
1924887Schin 					parts++;
1934887Schin 					/*FALLTHROUGH*/
1944887Schin 				case 1:
1954887Schin 					width = width * 10 + (c - '0');
1964887Schin 					break;
1974887Schin 				case 2:
1984887Schin 					prec = prec * 10 + (c - '0');
1994887Schin 					break;
2004887Schin 				}
2014887Schin 				continue;
2024887Schin 			case '.':
2034887Schin 				if (!parts++)
2044887Schin 					parts++;
2054887Schin 				continue;
20610898Sroland.mainz@nrubsig.org 			case '(':
20710898Sroland.mainz@nrubsig.org 				i = 1;
20810898Sroland.mainz@nrubsig.org 				arg = argbuf;
20910898Sroland.mainz@nrubsig.org 				for (;;)
21010898Sroland.mainz@nrubsig.org 				{
21110898Sroland.mainz@nrubsig.org 					if (!(c = *format++))
21210898Sroland.mainz@nrubsig.org 					{
21310898Sroland.mainz@nrubsig.org 						format--;
21410898Sroland.mainz@nrubsig.org 						break;
21510898Sroland.mainz@nrubsig.org 					}
21610898Sroland.mainz@nrubsig.org 					else if (c == '(')
21710898Sroland.mainz@nrubsig.org 						i++;
21810898Sroland.mainz@nrubsig.org 					else if (c == ')' && !--i)
21910898Sroland.mainz@nrubsig.org 						break;
22010898Sroland.mainz@nrubsig.org 					else if (arg < &argbuf[sizeof(argbuf) - 1])
22110898Sroland.mainz@nrubsig.org 						*arg++ = c;
22210898Sroland.mainz@nrubsig.org 				}
22310898Sroland.mainz@nrubsig.org 				*arg = 0;
22410898Sroland.mainz@nrubsig.org 				arg = argbuf;
22510898Sroland.mainz@nrubsig.org 				continue;
2264887Schin 			default:
2274887Schin 				break;
2284887Schin 			}
2294887Schin 			break;
2304887Schin 		}
2314887Schin 		switch (c)
2324887Schin 		{
2334887Schin 		case 0:
2344887Schin 			format--;
2354887Schin 			continue;
2364887Schin 		case '%':
2374887Schin 			if (cp < ep)
2384887Schin 				*cp++ = '%';
2394887Schin 			continue;
2404887Schin 		case '?':
2414887Schin 			if (tm_info.deformat != tm_info.format[TM_DEFAULT])
2424887Schin 				format = tm_info.deformat;
2434887Schin 			else if (!*format)
2444887Schin 				format = tm_info.format[TM_DEFAULT];
2454887Schin 			continue;
2464887Schin 		case 'a':	/* abbreviated day of week name */
24710898Sroland.mainz@nrubsig.org 			n = TM_DAY_ABBREV + tm->tm_wday;
2484887Schin 			goto index;
2494887Schin 		case 'A':	/* day of week name */
25010898Sroland.mainz@nrubsig.org 			n = TM_DAY + tm->tm_wday;
2514887Schin 			goto index;
2524887Schin 		case 'b':	/* abbreviated month name */
2534887Schin 		case 'h':
25410898Sroland.mainz@nrubsig.org 			n = TM_MONTH_ABBREV + tm->tm_mon;
2554887Schin 			goto index;
2564887Schin 		case 'B':	/* month name */
25710898Sroland.mainz@nrubsig.org 			n = TM_MONTH + tm->tm_mon;
2584887Schin 			goto index;
2594887Schin 		case 'c':	/* `ctime(3)' date sans newline */
2604887Schin 			p = tm_info.format[TM_CTIME];
2614887Schin 			goto push;
2624887Schin 		case 'C':	/* 2 digit century */
26310898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)(1900 + tm->tm_year) / 100, 2, width, pad);
2644887Schin 			continue;
2654887Schin 		case 'd':	/* day of month */
26610898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_mday, 2, width, pad);
2674887Schin 			continue;
2684887Schin 		case 'D':	/* date */
2694887Schin 			p = tm_info.format[TM_DATE];
2704887Schin 			goto push;
2714887Schin 		case 'E':       /* OBSOLETE no pad day of month */
27210898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_mday, 0, width, pad);
2734887Schin 			continue;
2744887Schin 		case 'e':       /* blank padded day of month */
27510898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_mday, -2, width, pad);
2764887Schin 			continue;
2774887Schin 		case 'f':	/* TM_DEFAULT override */
2784887Schin 			p = tm_info.deformat;
2794887Schin 			goto push;
2808462SApril.Chin@Sun.COM 		case 'F':	/* ISO 8601:2000 standard date format */
2818462SApril.Chin@Sun.COM 			p = "%Y-%m-%d";
2824887Schin 			goto push;
2834887Schin 		case 'g':	/* %V 2 digit year */
2844887Schin 		case 'G':	/* %V 4 digit year */
28510898Sroland.mainz@nrubsig.org 			n = tm->tm_year + 1900;
28610898Sroland.mainz@nrubsig.org 			if (tm->tm_yday < 7)
2874887Schin 			{
28810898Sroland.mainz@nrubsig.org 				if (tmweek(tm, 2, -1, -1) >= 52)
2894887Schin 					n--;
2904887Schin 			}
29110898Sroland.mainz@nrubsig.org 			else if (tm->tm_yday > 358)
2924887Schin 			{
29310898Sroland.mainz@nrubsig.org 				if (tmweek(tm, 2, -1, -1) <= 1)
2944887Schin 					n++;
2954887Schin 			}
2964887Schin 			if (c == 'g')
2974887Schin 			{
2984887Schin 				n %= 100;
2994887Schin 				c = 2;
3004887Schin 			}
3014887Schin 			else
3024887Schin 				c = 4;
3034887Schin 			cp = number(cp, ep, (long)n, c, width, pad);
3044887Schin 			continue;
3054887Schin 		case 'H':	/* hour (0 - 23) */
30610898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_hour, 2, width, pad);
3074887Schin 			continue;
3084887Schin 		case 'i':	/* international `date(1)' date */
3094887Schin 			p = tm_info.format[TM_INTERNATIONAL];
3104887Schin 			goto push;
3114887Schin 		case 'I':	/* hour (0 - 12) */
31210898Sroland.mainz@nrubsig.org 			if ((n = tm->tm_hour) > 12) n -= 12;
3134887Schin 			else if (n == 0) n = 12;
3144887Schin 			cp = number(cp, ep, (long)n, 2, width, pad);
3154887Schin 			continue;
3164887Schin 		case 'J':	/* Julian date (0 offset) */
31710898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_yday, 3, width, pad);
3184887Schin 			continue;
3194887Schin 		case 'j':	/* Julian date (1 offset) */
32010898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)(tm->tm_yday + 1), 3, width, pad);
3214887Schin 			continue;
3224887Schin 		case 'k':	/* `date(1)' date */
3234887Schin 			p = tm_info.format[TM_DATE_1];
3244887Schin 			goto push;
3254887Schin 		case 'K':
32610898Sroland.mainz@nrubsig.org 			switch (alt)
32710898Sroland.mainz@nrubsig.org 			{
32810898Sroland.mainz@nrubsig.org 			case 'E':
32910898Sroland.mainz@nrubsig.org 				p = (pad == '_') ? "%Y-%m-%d %H:%M:%S.%N %z" : "%Y-%m-%d+%H:%M:%S.%N%z";
33010898Sroland.mainz@nrubsig.org 				break;
33110898Sroland.mainz@nrubsig.org 			case 'O':
33210898Sroland.mainz@nrubsig.org 				p = (pad == '_') ? "%Y-%m-%d %H:%M:%S.%N" : "%Y-%m-%d+%H:%M:%S.%N";
33310898Sroland.mainz@nrubsig.org 				break;
33410898Sroland.mainz@nrubsig.org 			default:
33510898Sroland.mainz@nrubsig.org 				p = (pad == '_') ? "%Y-%m-%d %H:%M:%S" : "%Y-%m-%d+%H:%M:%S";
33610898Sroland.mainz@nrubsig.org 				break;
33710898Sroland.mainz@nrubsig.org 			}
3384887Schin 			goto push;
3394887Schin 		case 'l':	/* `ls -l' date */
3404887Schin 			if (t)
3414887Schin 			{
3424887Schin 				now = tmxgettime();
3434887Schin 				if (warped(t, now))
3444887Schin 				{
3454887Schin 					p = tm_info.format[TM_DISTANT];
3464887Schin 					goto push;
3474887Schin 				}
3484887Schin 			}
3494887Schin 			p = tm_info.format[TM_RECENT];
3504887Schin 			goto push;
3518462SApril.Chin@Sun.COM 		case 'L':	/* TM_DEFAULT */
3528462SApril.Chin@Sun.COM 		case 'O':	/* OBSOLETE */
3538462SApril.Chin@Sun.COM 			p = tm_info.format[TM_DEFAULT];
3548462SApril.Chin@Sun.COM 			goto push;
3554887Schin 		case 'm':	/* month number */
35610898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)(tm->tm_mon + 1), 2, width, pad);
3574887Schin 			continue;
3584887Schin 		case 'M':	/* minutes */
35910898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_min, 2, width, pad);
3604887Schin 			continue;
3614887Schin 		case 'n':
3624887Schin 			if (cp < ep)
3634887Schin 				*cp++ = '\n';
3644887Schin 			continue;
3654887Schin 		case 'N':	/* nanosecond part */
36610898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_nsec, 9, width, pad);
3674887Schin 			continue;
36810898Sroland.mainz@nrubsig.org 		case 'o':	/* set options */
36910898Sroland.mainz@nrubsig.org 			if (arg)
37010898Sroland.mainz@nrubsig.org 				goto options;
37110898Sroland.mainz@nrubsig.org 			/*OBSOLETE*/
37210898Sroland.mainz@nrubsig.org 			p = tm_info.deformat;
37310898Sroland.mainz@nrubsig.org 			goto push;
3744887Schin 		case 'p':	/* meridian */
37510898Sroland.mainz@nrubsig.org 			n = TM_MERIDIAN + (tm->tm_hour >= 12);
3764887Schin 			goto index;
3774887Schin 		case 'q':	/* time zone type (nation code) */
3784887Schin 			if (!(flags & TM_UTC))
3794887Schin 			{
38010898Sroland.mainz@nrubsig.org 				if ((zp = tm->tm_zone) != tm_info.local)
3814887Schin 					for (; zp >= tm_data.zone; zp--)
3824887Schin 						if (p = zp->type)
3834887Schin 							goto string;
3844887Schin 				else if (p = zp->type)
3854887Schin 					goto string;
3864887Schin 			}
3874887Schin 			continue;
3884887Schin 		case 'Q':	/* %Q<alpha> or %Q<delim>recent<delim>distant<delim> */
3894887Schin 			if (c = *format)
3904887Schin 			{
3914887Schin 				format++;
3924887Schin 				if (isalpha(c))
3934887Schin 				{
3944887Schin 					switch (c)
3954887Schin 					{
3964887Schin 					case 'd':	/* `ls -l' distant date */
3974887Schin 						p = tm_info.format[TM_DISTANT];
3984887Schin 						goto push;
3994887Schin 					case 'r':	/* `ls -l' recent date */
4004887Schin 						p = tm_info.format[TM_RECENT];
4014887Schin 						goto push;
4024887Schin 					default:
4034887Schin 						format--;
4044887Schin 						break;
4054887Schin 					}
4064887Schin 				}
4074887Schin 				else
4084887Schin 				{
4094887Schin 					if (t)
4104887Schin 					{
4114887Schin 						now = tmxgettime();
4124887Schin 						p = warped(t, now) ? (char*)0 : (char*)format;
4134887Schin 					}
4144887Schin 					else
4154887Schin 						p = (char*)format;
4164887Schin 					i = 0;
4174887Schin 					while (n = *format)
4184887Schin 					{
4194887Schin 						format++;
4204887Schin 						if (n == c)
4214887Schin 						{
4224887Schin 							if (!p)
4234887Schin 								p = (char*)format;
4244887Schin 							if (++i == 2)
4254887Schin 								goto push_delimiter;
4264887Schin 						}
4274887Schin 					}
4284887Schin 				}
4294887Schin 			}
4304887Schin 			continue;
4314887Schin 		case 'r':
4324887Schin 			p = tm_info.format[TM_MERIDIAN_TIME];
4334887Schin 			goto push;
4344887Schin 		case 'R':
4354887Schin 			p = "%H:%M";
4364887Schin 			goto push;
4374887Schin 		case 's':	/* seconds[.nanoseconds] since the epoch */
4384887Schin 		case '#':
43910898Sroland.mainz@nrubsig.org 			now = t;
4404887Schin 			f = fmt;
4414887Schin 			*f++ = '%';
4424887Schin 			if (pad == '0')
4434887Schin 				*f++ = pad;
4444887Schin 			if (width)
4454887Schin 				f += sfsprintf(f, &fmt[sizeof(fmt)] - f, "%d", width);
4464887Schin 			f += sfsprintf(f, &fmt[sizeof(fmt)] - f, "I%du", sizeof(Tmxsec_t));
4474887Schin 			cp += sfsprintf(cp, ep - cp, fmt, tmxsec(now));
4484887Schin 			if (parts > 1)
4494887Schin 			{
4504887Schin 				n = sfsprintf(cp, ep - cp, ".%09I*u", sizeof(Tmxnsec_t), tmxnsec(now));
4514887Schin 				if (prec && n >= prec)
4524887Schin 					n = prec + 1;
4534887Schin 				cp += n;
4544887Schin 			}
4554887Schin 			continue;
4564887Schin 		case 'S':	/* seconds */
45710898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_sec, 2, width, pad);
4584887Schin 			if ((flags & TM_SUBSECOND) && (format - 2) != oformat)
4594887Schin 			{
4604887Schin 				p = ".%N";
4614887Schin 				goto push;
4624887Schin 			}
4634887Schin 			continue;
4644887Schin 		case 't':
4654887Schin 			if (cp < ep)
4664887Schin 				*cp++ = '\t';
4674887Schin 			continue;
4684887Schin 		case 'T':
4694887Schin 			p = tm_info.format[TM_TIME];
4704887Schin 			goto push;
4714887Schin 		case 'u':	/* weekday number [1(Monday)-7] */
47210898Sroland.mainz@nrubsig.org 			if (!(i = tm->tm_wday))
4734887Schin 				i = 7;
4744887Schin 			cp = number(cp, ep, (long)i, 0, width, pad);
4754887Schin 			continue;
4764887Schin 		case 'U':	/* week number, Sunday as first day */
47710898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tmweek(tm, 0, -1, -1), 2, width, pad);
4784887Schin 			continue;
4794887Schin 		case 'V':	/* ISO week number */
48010898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tmweek(tm, 2, -1, -1), 2, width, pad);
4814887Schin 			continue;
4824887Schin 		case 'W':	/* week number, Monday as first day */
48310898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tmweek(tm, 1, -1, -1), 2, width, pad);
4844887Schin 			continue;
4854887Schin 		case 'w':	/* weekday number [0(Sunday)-6] */
48610898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)tm->tm_wday, 0, width, pad);
4874887Schin 			continue;
4884887Schin 		case 'x':
4894887Schin 			p = tm_info.format[TM_DATE];
4904887Schin 			goto push;
4914887Schin 		case 'X':
4924887Schin 			p = tm_info.format[TM_TIME];
4934887Schin 			goto push;
4944887Schin 		case 'y':	/* year in the form yy */
49510898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)(tm->tm_year % 100), 2, width, pad);
4964887Schin 			continue;
4974887Schin 		case 'Y':	/* year in the form ccyy */
49810898Sroland.mainz@nrubsig.org 			cp = number(cp, ep, (long)(1900 + tm->tm_year), 4, width, pad);
4994887Schin 			continue;
5004887Schin 		case 'z':	/* time zone west offset */
50110898Sroland.mainz@nrubsig.org 			if (arg)
50210898Sroland.mainz@nrubsig.org 			{
50310898Sroland.mainz@nrubsig.org 				if ((zp = tmzone(arg, &f, 0, 0)) && !*f && tm->tm_zone != zp)
50410898Sroland.mainz@nrubsig.org 					tm = tmxtm(tm, tmxtime(tm, tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0)), zp);
50510898Sroland.mainz@nrubsig.org 				continue;
50610898Sroland.mainz@nrubsig.org 			}
5074887Schin 			if ((ep - cp) >= 16)
50810898Sroland.mainz@nrubsig.org 				cp = tmpoff(cp, ep - cp, "", (flags & TM_UTC) ? 0 : tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0), 24 * 60);
5094887Schin 			continue;
5104887Schin 		case 'Z':	/* time zone */
51110898Sroland.mainz@nrubsig.org 			if (arg)
51210898Sroland.mainz@nrubsig.org 			{
51310898Sroland.mainz@nrubsig.org 				if ((zp = tmzone(arg, &f, 0, 0)) && !*f && tm->tm_zone != zp)
51410898Sroland.mainz@nrubsig.org 					tm = tmxtm(tm, tmxtime(tm, tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0)), zp);
51510898Sroland.mainz@nrubsig.org 				continue;
51610898Sroland.mainz@nrubsig.org 			}
51710898Sroland.mainz@nrubsig.org 			p = (flags & TM_UTC) ? tm_info.format[TM_UT] : tm->tm_isdst && tm->tm_zone->daylight ? tm->tm_zone->daylight : tm->tm_zone->standard;
5184887Schin 			goto string;
5194887Schin 		case '+':	/* old %+flag */
5204887Schin 		case '!':	/* old %!flag */
5214887Schin 			format--;
5224887Schin 			/*FALLTHROUGH*/
52310898Sroland.mainz@nrubsig.org 		case '=':	/* old %=[=][+-]flag */
52410898Sroland.mainz@nrubsig.org 			for (arg = argbuf; *format == '=' || *format == '-' || *format == '+' || *format == '!'; format++)
52510898Sroland.mainz@nrubsig.org 				if (arg < &argbuf[sizeof(argbuf) - 2])
52610898Sroland.mainz@nrubsig.org 					*arg++ = *format;
52710898Sroland.mainz@nrubsig.org 			if (*arg++ = *format)
5284887Schin 				format++;
52910898Sroland.mainz@nrubsig.org 			*arg = 0;
53010898Sroland.mainz@nrubsig.org 			arg = argbuf;
53110898Sroland.mainz@nrubsig.org 			goto options;
5324887Schin 		default:
5334887Schin 			if (cp < ep)
5344887Schin 				*cp++ = '%';
5354887Schin 			if (cp < ep)
5364887Schin 				*cp++ = c;
5374887Schin 			continue;
5384887Schin 		}
5394887Schin 	index:
5404887Schin 		p = tm_info.format[n];
5414887Schin 	string:
5424887Schin 		while (cp < ep && (*cp = *p++))
5434887Schin 			cp++;
5444887Schin 		continue;
54510898Sroland.mainz@nrubsig.org 	options:
54610898Sroland.mainz@nrubsig.org 		c = '+';
54710898Sroland.mainz@nrubsig.org 		i = 0;
54810898Sroland.mainz@nrubsig.org 		for (;;)
54910898Sroland.mainz@nrubsig.org 		{
55010898Sroland.mainz@nrubsig.org 			switch (*arg++)
55110898Sroland.mainz@nrubsig.org 			{
55210898Sroland.mainz@nrubsig.org 			case 0:
55310898Sroland.mainz@nrubsig.org 				n = 0;
55410898Sroland.mainz@nrubsig.org 				break;
55510898Sroland.mainz@nrubsig.org 			case '=':
55610898Sroland.mainz@nrubsig.org 				i = !i;
55710898Sroland.mainz@nrubsig.org 				continue;
55810898Sroland.mainz@nrubsig.org 			case '+':
55910898Sroland.mainz@nrubsig.org 			case '-':
56010898Sroland.mainz@nrubsig.org 			case '!':
56110898Sroland.mainz@nrubsig.org 				c = *(arg - 1);
56210898Sroland.mainz@nrubsig.org 				continue;
56310898Sroland.mainz@nrubsig.org 			case 'l':
56410898Sroland.mainz@nrubsig.org 				n = TM_LEAP;
56510898Sroland.mainz@nrubsig.org 				break;
56610898Sroland.mainz@nrubsig.org 			case 'n':
56710898Sroland.mainz@nrubsig.org 			case 's':
56810898Sroland.mainz@nrubsig.org 				n = TM_SUBSECOND;
56910898Sroland.mainz@nrubsig.org 				break;
57010898Sroland.mainz@nrubsig.org 			case 'u':
57110898Sroland.mainz@nrubsig.org 				n = TM_UTC;
57210898Sroland.mainz@nrubsig.org 				break;
57310898Sroland.mainz@nrubsig.org 			default:
57410898Sroland.mainz@nrubsig.org 				continue;
57510898Sroland.mainz@nrubsig.org 			}
57610898Sroland.mainz@nrubsig.org 			if (!n)
57710898Sroland.mainz@nrubsig.org 				break;
57810898Sroland.mainz@nrubsig.org 
57910898Sroland.mainz@nrubsig.org 			/*
58010898Sroland.mainz@nrubsig.org 			 * right, the global state stinks
58110898Sroland.mainz@nrubsig.org 			 * but we respect its locale-like status
58210898Sroland.mainz@nrubsig.org 			 */
58310898Sroland.mainz@nrubsig.org 
58410898Sroland.mainz@nrubsig.org 			if (c == '+')
58510898Sroland.mainz@nrubsig.org 			{
58610898Sroland.mainz@nrubsig.org 				if (!(flags & n))
58710898Sroland.mainz@nrubsig.org 				{
58810898Sroland.mainz@nrubsig.org 					flags |= n;
58910898Sroland.mainz@nrubsig.org 					tm_info.flags |= n;
59010898Sroland.mainz@nrubsig.org 					tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone);
59110898Sroland.mainz@nrubsig.org 					if (!i)
59210898Sroland.mainz@nrubsig.org 						tm_info.flags &= ~n;
59310898Sroland.mainz@nrubsig.org 				}
59410898Sroland.mainz@nrubsig.org 			}
59510898Sroland.mainz@nrubsig.org 			else if (flags & n)
59610898Sroland.mainz@nrubsig.org 			{
59710898Sroland.mainz@nrubsig.org 				flags &= ~n;
59810898Sroland.mainz@nrubsig.org 				tm_info.flags &= ~n;
59910898Sroland.mainz@nrubsig.org 				tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone);
60010898Sroland.mainz@nrubsig.org 				if (!i)
60110898Sroland.mainz@nrubsig.org 					tm_info.flags |= n;
60210898Sroland.mainz@nrubsig.org 			}
60310898Sroland.mainz@nrubsig.org 		}
60410898Sroland.mainz@nrubsig.org 		continue;
6054887Schin 	push:
6064887Schin 		c = 0;
6074887Schin 	push_delimiter:
6084887Schin 		if (sp < &stack[elementsof(stack)])
6094887Schin 		{
6104887Schin 			sp->format = (char*)format;
6114887Schin 			format = p;
6124887Schin 			sp->delimiter = delimiter;
6134887Schin 			delimiter = c;
6144887Schin 			sp++;
6154887Schin 		}
6164887Schin 		continue;
6174887Schin 	}
6184887Schin 	tm_info.flags = flags;
6194887Schin 	if (cp >= ep)
6204887Schin 		cp = ep - 1;
6214887Schin 	*cp = 0;
6224887Schin 	return cp;
6234887Schin }
624