1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1985-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> *
18da2e3ebdSchin * David Korn <dgk@research.att.com> *
19da2e3ebdSchin * Phong Vo <kpv@research.att.com> *
20da2e3ebdSchin * *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin * Glenn Fowler
25da2e3ebdSchin * AT&T Research
26da2e3ebdSchin *
27da2e3ebdSchin * Time_t conversion support
28da2e3ebdSchin */
29da2e3ebdSchin
30da2e3ebdSchin #include <tmx.h>
31da2e3ebdSchin #include <ctype.h>
32da2e3ebdSchin
33da2e3ebdSchin #define warped(t,n) ((t)<((n)-tmxsns(6L*30L*24L*60L*60L,0))||(t)>((n)+tmxsns(24L*60L*60L,0)))
34da2e3ebdSchin
35da2e3ebdSchin /*
36da2e3ebdSchin * format n with padding p into s
37da2e3ebdSchin * return end of s
38da2e3ebdSchin *
39da2e3ebdSchin * p: <0 blank padding
40da2e3ebdSchin * 0 no padding
41da2e3ebdSchin * >0 0 padding
42da2e3ebdSchin */
43da2e3ebdSchin
44da2e3ebdSchin static char*
number(register char * s,register char * e,register long n,register int p,int w,int pad)45da2e3ebdSchin number(register char* s, register char* e, register long n, register int p, int w, int pad)
46da2e3ebdSchin {
47da2e3ebdSchin char* b;
48da2e3ebdSchin
497c2fbfb3SApril Chin if (w)
507c2fbfb3SApril Chin {
517c2fbfb3SApril Chin if (p > 0 && (pad == 0 || pad == '0'))
527c2fbfb3SApril Chin while (w > p)
537c2fbfb3SApril Chin {
547c2fbfb3SApril Chin p++;
557c2fbfb3SApril Chin n *= 10;
567c2fbfb3SApril Chin }
577c2fbfb3SApril Chin else if (w > p)
58da2e3ebdSchin p = w;
597c2fbfb3SApril Chin }
60da2e3ebdSchin switch (pad)
61da2e3ebdSchin {
62da2e3ebdSchin case '-':
63da2e3ebdSchin p = 0;
64da2e3ebdSchin break;
65da2e3ebdSchin case '_':
66da2e3ebdSchin if (p > 0)
67da2e3ebdSchin p = -p;
68da2e3ebdSchin break;
69da2e3ebdSchin case '0':
70da2e3ebdSchin if (p < 0)
71da2e3ebdSchin p = -p;
72da2e3ebdSchin break;
73da2e3ebdSchin }
74da2e3ebdSchin b = s;
75da2e3ebdSchin if (p > 0)
76da2e3ebdSchin s += sfsprintf(s, e - s, "%0*lu", p, n);
77da2e3ebdSchin else if (p < 0)
78da2e3ebdSchin s += sfsprintf(s, e - s, "%*lu", -p, n);
79da2e3ebdSchin else
80da2e3ebdSchin s += sfsprintf(s, e - s, "%lu", n);
81da2e3ebdSchin if (w && (s - b) > w)
82da2e3ebdSchin *(s = b + w) = 0;
83da2e3ebdSchin return s;
84da2e3ebdSchin }
85da2e3ebdSchin
86da2e3ebdSchin typedef struct Stack_s
87da2e3ebdSchin {
88da2e3ebdSchin char* format;
89da2e3ebdSchin int delimiter;
90da2e3ebdSchin } Stack_t;
91da2e3ebdSchin
92da2e3ebdSchin /*
93da2e3ebdSchin * format t into buf of length len
94da2e3ebdSchin * end of buf is returned
95da2e3ebdSchin */
96da2e3ebdSchin
97da2e3ebdSchin char*
tmxfmt(char * buf,size_t len,const char * format,Time_t t)98da2e3ebdSchin tmxfmt(char* buf, size_t len, const char* format, Time_t t)
99da2e3ebdSchin {
100da2e3ebdSchin register char* cp;
101da2e3ebdSchin register char* ep;
102da2e3ebdSchin register char* p;
103da2e3ebdSchin register int n;
104da2e3ebdSchin int c;
105da2e3ebdSchin int i;
106da2e3ebdSchin int flags;
10734f9b3eeSRoland Mainz int alt;
108da2e3ebdSchin int pad;
109da2e3ebdSchin int delimiter;
110da2e3ebdSchin int width;
111da2e3ebdSchin int prec;
112da2e3ebdSchin int parts;
11334f9b3eeSRoland Mainz char* arg;
114da2e3ebdSchin char* f;
115da2e3ebdSchin const char* oformat;
11634f9b3eeSRoland Mainz Tm_t* tm;
117da2e3ebdSchin Tm_zone_t* zp;
118da2e3ebdSchin Time_t now;
119da2e3ebdSchin Stack_t* sp;
120da2e3ebdSchin Stack_t stack[8];
12134f9b3eeSRoland Mainz Tm_t ts;
12234f9b3eeSRoland Mainz char argbuf[256];
123da2e3ebdSchin char fmt[32];
124da2e3ebdSchin
125da2e3ebdSchin tmlocale();
12634f9b3eeSRoland Mainz tm = tmxtm(&ts, t, NiL);
127da2e3ebdSchin if (!format || !*format)
128da2e3ebdSchin format = tm_info.deformat;
129da2e3ebdSchin oformat = format;
130da2e3ebdSchin flags = tm_info.flags;
131da2e3ebdSchin sp = &stack[0];
132da2e3ebdSchin cp = buf;
133da2e3ebdSchin ep = buf + len;
134da2e3ebdSchin delimiter = 0;
135da2e3ebdSchin for (;;)
136da2e3ebdSchin {
137da2e3ebdSchin if ((c = *format++) == delimiter)
138da2e3ebdSchin {
139da2e3ebdSchin delimiter = 0;
140da2e3ebdSchin if (sp <= &stack[0])
141da2e3ebdSchin break;
142da2e3ebdSchin sp--;
143da2e3ebdSchin format = sp->format;
144da2e3ebdSchin delimiter = sp->delimiter;
145da2e3ebdSchin continue;
146da2e3ebdSchin }
147da2e3ebdSchin if (c != '%')
148da2e3ebdSchin {
149da2e3ebdSchin if (cp < ep)
150da2e3ebdSchin *cp++ = c;
151da2e3ebdSchin continue;
152da2e3ebdSchin }
15334f9b3eeSRoland Mainz alt = 0;
15434f9b3eeSRoland Mainz arg = 0;
155da2e3ebdSchin pad = 0;
156da2e3ebdSchin width = 0;
157da2e3ebdSchin prec = 0;
158da2e3ebdSchin parts = 0;
159da2e3ebdSchin for (;;)
160da2e3ebdSchin {
161da2e3ebdSchin switch (c = *format++)
162da2e3ebdSchin {
163da2e3ebdSchin case '_':
164da2e3ebdSchin case '-':
165da2e3ebdSchin pad = c;
166da2e3ebdSchin continue;
167da2e3ebdSchin case 'E':
168da2e3ebdSchin case 'O':
169da2e3ebdSchin if (!isalpha(*format))
170da2e3ebdSchin break;
17134f9b3eeSRoland Mainz alt = c;
172da2e3ebdSchin continue;
173da2e3ebdSchin case '0':
174da2e3ebdSchin if (!parts)
175da2e3ebdSchin {
176da2e3ebdSchin pad = c;
177da2e3ebdSchin continue;
178da2e3ebdSchin }
179da2e3ebdSchin /*FALLTHROUGH*/
180da2e3ebdSchin case '1':
181da2e3ebdSchin case '2':
182da2e3ebdSchin case '3':
183da2e3ebdSchin case '4':
184da2e3ebdSchin case '5':
185da2e3ebdSchin case '6':
186da2e3ebdSchin case '7':
187da2e3ebdSchin case '8':
188da2e3ebdSchin case '9':
189da2e3ebdSchin switch (parts)
190da2e3ebdSchin {
191da2e3ebdSchin case 0:
192da2e3ebdSchin parts++;
193da2e3ebdSchin /*FALLTHROUGH*/
194da2e3ebdSchin case 1:
195da2e3ebdSchin width = width * 10 + (c - '0');
196da2e3ebdSchin break;
197da2e3ebdSchin case 2:
198da2e3ebdSchin prec = prec * 10 + (c - '0');
199da2e3ebdSchin break;
200da2e3ebdSchin }
201da2e3ebdSchin continue;
202da2e3ebdSchin case '.':
203da2e3ebdSchin if (!parts++)
204da2e3ebdSchin parts++;
205da2e3ebdSchin continue;
20634f9b3eeSRoland Mainz case '(':
20734f9b3eeSRoland Mainz i = 1;
20834f9b3eeSRoland Mainz arg = argbuf;
20934f9b3eeSRoland Mainz for (;;)
21034f9b3eeSRoland Mainz {
21134f9b3eeSRoland Mainz if (!(c = *format++))
21234f9b3eeSRoland Mainz {
21334f9b3eeSRoland Mainz format--;
21434f9b3eeSRoland Mainz break;
21534f9b3eeSRoland Mainz }
21634f9b3eeSRoland Mainz else if (c == '(')
21734f9b3eeSRoland Mainz i++;
21834f9b3eeSRoland Mainz else if (c == ')' && !--i)
21934f9b3eeSRoland Mainz break;
22034f9b3eeSRoland Mainz else if (arg < &argbuf[sizeof(argbuf) - 1])
22134f9b3eeSRoland Mainz *arg++ = c;
22234f9b3eeSRoland Mainz }
22334f9b3eeSRoland Mainz *arg = 0;
22434f9b3eeSRoland Mainz arg = argbuf;
22534f9b3eeSRoland Mainz continue;
226da2e3ebdSchin default:
227da2e3ebdSchin break;
228da2e3ebdSchin }
229da2e3ebdSchin break;
230da2e3ebdSchin }
231da2e3ebdSchin switch (c)
232da2e3ebdSchin {
233da2e3ebdSchin case 0:
234da2e3ebdSchin format--;
235da2e3ebdSchin continue;
236da2e3ebdSchin case '%':
237da2e3ebdSchin if (cp < ep)
238da2e3ebdSchin *cp++ = '%';
239da2e3ebdSchin continue;
240da2e3ebdSchin case '?':
241da2e3ebdSchin if (tm_info.deformat != tm_info.format[TM_DEFAULT])
242da2e3ebdSchin format = tm_info.deformat;
243da2e3ebdSchin else if (!*format)
244da2e3ebdSchin format = tm_info.format[TM_DEFAULT];
245da2e3ebdSchin continue;
246da2e3ebdSchin case 'a': /* abbreviated day of week name */
24734f9b3eeSRoland Mainz n = TM_DAY_ABBREV + tm->tm_wday;
248da2e3ebdSchin goto index;
249da2e3ebdSchin case 'A': /* day of week name */
25034f9b3eeSRoland Mainz n = TM_DAY + tm->tm_wday;
251da2e3ebdSchin goto index;
252da2e3ebdSchin case 'b': /* abbreviated month name */
253da2e3ebdSchin case 'h':
25434f9b3eeSRoland Mainz n = TM_MONTH_ABBREV + tm->tm_mon;
255da2e3ebdSchin goto index;
256da2e3ebdSchin case 'B': /* month name */
25734f9b3eeSRoland Mainz n = TM_MONTH + tm->tm_mon;
258da2e3ebdSchin goto index;
259da2e3ebdSchin case 'c': /* `ctime(3)' date sans newline */
260da2e3ebdSchin p = tm_info.format[TM_CTIME];
261da2e3ebdSchin goto push;
262da2e3ebdSchin case 'C': /* 2 digit century */
26334f9b3eeSRoland Mainz cp = number(cp, ep, (long)(1900 + tm->tm_year) / 100, 2, width, pad);
264da2e3ebdSchin continue;
265da2e3ebdSchin case 'd': /* day of month */
26634f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_mday, 2, width, pad);
267da2e3ebdSchin continue;
268da2e3ebdSchin case 'D': /* date */
269da2e3ebdSchin p = tm_info.format[TM_DATE];
270da2e3ebdSchin goto push;
271da2e3ebdSchin case 'E': /* OBSOLETE no pad day of month */
27234f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_mday, 0, width, pad);
273da2e3ebdSchin continue;
274da2e3ebdSchin case 'e': /* blank padded day of month */
27534f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_mday, -2, width, pad);
276da2e3ebdSchin continue;
277da2e3ebdSchin case 'f': /* TM_DEFAULT override */
278da2e3ebdSchin p = tm_info.deformat;
279da2e3ebdSchin goto push;
2807c2fbfb3SApril Chin case 'F': /* ISO 8601:2000 standard date format */
2817c2fbfb3SApril Chin p = "%Y-%m-%d";
282da2e3ebdSchin goto push;
283da2e3ebdSchin case 'g': /* %V 2 digit year */
284da2e3ebdSchin case 'G': /* %V 4 digit year */
28534f9b3eeSRoland Mainz n = tm->tm_year + 1900;
28634f9b3eeSRoland Mainz if (tm->tm_yday < 7)
287da2e3ebdSchin {
28834f9b3eeSRoland Mainz if (tmweek(tm, 2, -1, -1) >= 52)
289da2e3ebdSchin n--;
290da2e3ebdSchin }
29134f9b3eeSRoland Mainz else if (tm->tm_yday > 358)
292da2e3ebdSchin {
29334f9b3eeSRoland Mainz if (tmweek(tm, 2, -1, -1) <= 1)
294da2e3ebdSchin n++;
295da2e3ebdSchin }
296da2e3ebdSchin if (c == 'g')
297da2e3ebdSchin {
298da2e3ebdSchin n %= 100;
299da2e3ebdSchin c = 2;
300da2e3ebdSchin }
301da2e3ebdSchin else
302da2e3ebdSchin c = 4;
303da2e3ebdSchin cp = number(cp, ep, (long)n, c, width, pad);
304da2e3ebdSchin continue;
305da2e3ebdSchin case 'H': /* hour (0 - 23) */
30634f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_hour, 2, width, pad);
307da2e3ebdSchin continue;
308da2e3ebdSchin case 'i': /* international `date(1)' date */
309da2e3ebdSchin p = tm_info.format[TM_INTERNATIONAL];
310da2e3ebdSchin goto push;
311da2e3ebdSchin case 'I': /* hour (0 - 12) */
31234f9b3eeSRoland Mainz if ((n = tm->tm_hour) > 12) n -= 12;
313da2e3ebdSchin else if (n == 0) n = 12;
314da2e3ebdSchin cp = number(cp, ep, (long)n, 2, width, pad);
315da2e3ebdSchin continue;
316da2e3ebdSchin case 'J': /* Julian date (0 offset) */
31734f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_yday, 3, width, pad);
318da2e3ebdSchin continue;
319da2e3ebdSchin case 'j': /* Julian date (1 offset) */
32034f9b3eeSRoland Mainz cp = number(cp, ep, (long)(tm->tm_yday + 1), 3, width, pad);
321da2e3ebdSchin continue;
322da2e3ebdSchin case 'k': /* `date(1)' date */
323da2e3ebdSchin p = tm_info.format[TM_DATE_1];
324da2e3ebdSchin goto push;
325da2e3ebdSchin case 'K':
32634f9b3eeSRoland Mainz switch (alt)
32734f9b3eeSRoland Mainz {
32834f9b3eeSRoland Mainz case 'E':
32934f9b3eeSRoland Mainz p = (pad == '_') ? "%Y-%m-%d %H:%M:%S.%N %z" : "%Y-%m-%d+%H:%M:%S.%N%z";
33034f9b3eeSRoland Mainz break;
33134f9b3eeSRoland Mainz case 'O':
33234f9b3eeSRoland Mainz p = (pad == '_') ? "%Y-%m-%d %H:%M:%S.%N" : "%Y-%m-%d+%H:%M:%S.%N";
33334f9b3eeSRoland Mainz break;
33434f9b3eeSRoland Mainz default:
33534f9b3eeSRoland Mainz p = (pad == '_') ? "%Y-%m-%d %H:%M:%S" : "%Y-%m-%d+%H:%M:%S";
33634f9b3eeSRoland Mainz break;
33734f9b3eeSRoland Mainz }
338da2e3ebdSchin goto push;
339da2e3ebdSchin case 'l': /* `ls -l' date */
340da2e3ebdSchin if (t)
341da2e3ebdSchin {
342da2e3ebdSchin now = tmxgettime();
343da2e3ebdSchin if (warped(t, now))
344da2e3ebdSchin {
345da2e3ebdSchin p = tm_info.format[TM_DISTANT];
346da2e3ebdSchin goto push;
347da2e3ebdSchin }
348da2e3ebdSchin }
349da2e3ebdSchin p = tm_info.format[TM_RECENT];
350da2e3ebdSchin goto push;
3517c2fbfb3SApril Chin case 'L': /* TM_DEFAULT */
3527c2fbfb3SApril Chin case 'O': /* OBSOLETE */
3537c2fbfb3SApril Chin p = tm_info.format[TM_DEFAULT];
3547c2fbfb3SApril Chin goto push;
355da2e3ebdSchin case 'm': /* month number */
35634f9b3eeSRoland Mainz cp = number(cp, ep, (long)(tm->tm_mon + 1), 2, width, pad);
357da2e3ebdSchin continue;
358da2e3ebdSchin case 'M': /* minutes */
35934f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_min, 2, width, pad);
360da2e3ebdSchin continue;
361da2e3ebdSchin case 'n':
362da2e3ebdSchin if (cp < ep)
363da2e3ebdSchin *cp++ = '\n';
364da2e3ebdSchin continue;
365da2e3ebdSchin case 'N': /* nanosecond part */
36634f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_nsec, 9, width, pad);
367da2e3ebdSchin continue;
36834f9b3eeSRoland Mainz case 'o': /* set options */
36934f9b3eeSRoland Mainz if (arg)
37034f9b3eeSRoland Mainz goto options;
37134f9b3eeSRoland Mainz /*OBSOLETE*/
37234f9b3eeSRoland Mainz p = tm_info.deformat;
37334f9b3eeSRoland Mainz goto push;
374da2e3ebdSchin case 'p': /* meridian */
37534f9b3eeSRoland Mainz n = TM_MERIDIAN + (tm->tm_hour >= 12);
376da2e3ebdSchin goto index;
377da2e3ebdSchin case 'q': /* time zone type (nation code) */
378da2e3ebdSchin if (!(flags & TM_UTC))
379da2e3ebdSchin {
38034f9b3eeSRoland Mainz if ((zp = tm->tm_zone) != tm_info.local)
381da2e3ebdSchin for (; zp >= tm_data.zone; zp--)
382da2e3ebdSchin if (p = zp->type)
383da2e3ebdSchin goto string;
384da2e3ebdSchin else if (p = zp->type)
385da2e3ebdSchin goto string;
386da2e3ebdSchin }
387da2e3ebdSchin continue;
388da2e3ebdSchin case 'Q': /* %Q<alpha> or %Q<delim>recent<delim>distant<delim> */
389da2e3ebdSchin if (c = *format)
390da2e3ebdSchin {
391da2e3ebdSchin format++;
392da2e3ebdSchin if (isalpha(c))
393da2e3ebdSchin {
394da2e3ebdSchin switch (c)
395da2e3ebdSchin {
396da2e3ebdSchin case 'd': /* `ls -l' distant date */
397da2e3ebdSchin p = tm_info.format[TM_DISTANT];
398da2e3ebdSchin goto push;
399da2e3ebdSchin case 'r': /* `ls -l' recent date */
400da2e3ebdSchin p = tm_info.format[TM_RECENT];
401da2e3ebdSchin goto push;
402da2e3ebdSchin default:
403da2e3ebdSchin format--;
404da2e3ebdSchin break;
405da2e3ebdSchin }
406da2e3ebdSchin }
407da2e3ebdSchin else
408da2e3ebdSchin {
409da2e3ebdSchin if (t)
410da2e3ebdSchin {
411da2e3ebdSchin now = tmxgettime();
412da2e3ebdSchin p = warped(t, now) ? (char*)0 : (char*)format;
413da2e3ebdSchin }
414da2e3ebdSchin else
415da2e3ebdSchin p = (char*)format;
416da2e3ebdSchin i = 0;
417da2e3ebdSchin while (n = *format)
418da2e3ebdSchin {
419da2e3ebdSchin format++;
420da2e3ebdSchin if (n == c)
421da2e3ebdSchin {
422da2e3ebdSchin if (!p)
423da2e3ebdSchin p = (char*)format;
424da2e3ebdSchin if (++i == 2)
425da2e3ebdSchin goto push_delimiter;
426da2e3ebdSchin }
427da2e3ebdSchin }
428da2e3ebdSchin }
429da2e3ebdSchin }
430da2e3ebdSchin continue;
431da2e3ebdSchin case 'r':
432da2e3ebdSchin p = tm_info.format[TM_MERIDIAN_TIME];
433da2e3ebdSchin goto push;
434da2e3ebdSchin case 'R':
435da2e3ebdSchin p = "%H:%M";
436da2e3ebdSchin goto push;
437da2e3ebdSchin case 's': /* seconds[.nanoseconds] since the epoch */
438da2e3ebdSchin case '#':
439da2e3ebdSchin now = t;
440da2e3ebdSchin f = fmt;
441da2e3ebdSchin *f++ = '%';
442da2e3ebdSchin if (pad == '0')
443da2e3ebdSchin *f++ = pad;
444da2e3ebdSchin if (width)
445da2e3ebdSchin f += sfsprintf(f, &fmt[sizeof(fmt)] - f, "%d", width);
446da2e3ebdSchin f += sfsprintf(f, &fmt[sizeof(fmt)] - f, "I%du", sizeof(Tmxsec_t));
447da2e3ebdSchin cp += sfsprintf(cp, ep - cp, fmt, tmxsec(now));
448da2e3ebdSchin if (parts > 1)
449da2e3ebdSchin {
450da2e3ebdSchin n = sfsprintf(cp, ep - cp, ".%09I*u", sizeof(Tmxnsec_t), tmxnsec(now));
451da2e3ebdSchin if (prec && n >= prec)
452da2e3ebdSchin n = prec + 1;
453da2e3ebdSchin cp += n;
454da2e3ebdSchin }
455da2e3ebdSchin continue;
456da2e3ebdSchin case 'S': /* seconds */
45734f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_sec, 2, width, pad);
458da2e3ebdSchin if ((flags & TM_SUBSECOND) && (format - 2) != oformat)
459da2e3ebdSchin {
460da2e3ebdSchin p = ".%N";
461da2e3ebdSchin goto push;
462da2e3ebdSchin }
463da2e3ebdSchin continue;
464da2e3ebdSchin case 't':
465da2e3ebdSchin if (cp < ep)
466da2e3ebdSchin *cp++ = '\t';
467da2e3ebdSchin continue;
468da2e3ebdSchin case 'T':
469da2e3ebdSchin p = tm_info.format[TM_TIME];
470da2e3ebdSchin goto push;
471da2e3ebdSchin case 'u': /* weekday number [1(Monday)-7] */
47234f9b3eeSRoland Mainz if (!(i = tm->tm_wday))
473da2e3ebdSchin i = 7;
474da2e3ebdSchin cp = number(cp, ep, (long)i, 0, width, pad);
475da2e3ebdSchin continue;
476da2e3ebdSchin case 'U': /* week number, Sunday as first day */
47734f9b3eeSRoland Mainz cp = number(cp, ep, (long)tmweek(tm, 0, -1, -1), 2, width, pad);
478da2e3ebdSchin continue;
479da2e3ebdSchin case 'V': /* ISO week number */
48034f9b3eeSRoland Mainz cp = number(cp, ep, (long)tmweek(tm, 2, -1, -1), 2, width, pad);
481da2e3ebdSchin continue;
482da2e3ebdSchin case 'W': /* week number, Monday as first day */
48334f9b3eeSRoland Mainz cp = number(cp, ep, (long)tmweek(tm, 1, -1, -1), 2, width, pad);
484da2e3ebdSchin continue;
485da2e3ebdSchin case 'w': /* weekday number [0(Sunday)-6] */
48634f9b3eeSRoland Mainz cp = number(cp, ep, (long)tm->tm_wday, 0, width, pad);
487da2e3ebdSchin continue;
488da2e3ebdSchin case 'x':
489da2e3ebdSchin p = tm_info.format[TM_DATE];
490da2e3ebdSchin goto push;
491da2e3ebdSchin case 'X':
492da2e3ebdSchin p = tm_info.format[TM_TIME];
493da2e3ebdSchin goto push;
494da2e3ebdSchin case 'y': /* year in the form yy */
49534f9b3eeSRoland Mainz cp = number(cp, ep, (long)(tm->tm_year % 100), 2, width, pad);
496da2e3ebdSchin continue;
497da2e3ebdSchin case 'Y': /* year in the form ccyy */
49834f9b3eeSRoland Mainz cp = number(cp, ep, (long)(1900 + tm->tm_year), 4, width, pad);
499da2e3ebdSchin continue;
500da2e3ebdSchin case 'z': /* time zone west offset */
50134f9b3eeSRoland Mainz if (arg)
50234f9b3eeSRoland Mainz {
50334f9b3eeSRoland Mainz if ((zp = tmzone(arg, &f, 0, 0)) && !*f && tm->tm_zone != zp)
50434f9b3eeSRoland Mainz tm = tmxtm(tm, tmxtime(tm, tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0)), zp);
50534f9b3eeSRoland Mainz continue;
50634f9b3eeSRoland Mainz }
507da2e3ebdSchin if ((ep - cp) >= 16)
50834f9b3eeSRoland Mainz cp = tmpoff(cp, ep - cp, "", (flags & TM_UTC) ? 0 : tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0), 24 * 60);
509da2e3ebdSchin continue;
510da2e3ebdSchin case 'Z': /* time zone */
51134f9b3eeSRoland Mainz if (arg)
51234f9b3eeSRoland Mainz {
51334f9b3eeSRoland Mainz if ((zp = tmzone(arg, &f, 0, 0)) && !*f && tm->tm_zone != zp)
51434f9b3eeSRoland Mainz tm = tmxtm(tm, tmxtime(tm, tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0)), zp);
51534f9b3eeSRoland Mainz continue;
51634f9b3eeSRoland Mainz }
51734f9b3eeSRoland Mainz p = (flags & TM_UTC) ? tm_info.format[TM_UT] : tm->tm_isdst && tm->tm_zone->daylight ? tm->tm_zone->daylight : tm->tm_zone->standard;
518da2e3ebdSchin goto string;
519da2e3ebdSchin case '+': /* old %+flag */
520da2e3ebdSchin case '!': /* old %!flag */
521da2e3ebdSchin format--;
522da2e3ebdSchin /*FALLTHROUGH*/
52334f9b3eeSRoland Mainz case '=': /* old %=[=][+-]flag */
52434f9b3eeSRoland Mainz for (arg = argbuf; *format == '=' || *format == '-' || *format == '+' || *format == '!'; format++)
52534f9b3eeSRoland Mainz if (arg < &argbuf[sizeof(argbuf) - 2])
52634f9b3eeSRoland Mainz *arg++ = *format;
52734f9b3eeSRoland Mainz if (*arg++ = *format)
528da2e3ebdSchin format++;
52934f9b3eeSRoland Mainz *arg = 0;
53034f9b3eeSRoland Mainz arg = argbuf;
53134f9b3eeSRoland Mainz goto options;
532da2e3ebdSchin default:
533da2e3ebdSchin if (cp < ep)
534da2e3ebdSchin *cp++ = '%';
535da2e3ebdSchin if (cp < ep)
536da2e3ebdSchin *cp++ = c;
537da2e3ebdSchin continue;
538da2e3ebdSchin }
539da2e3ebdSchin index:
540da2e3ebdSchin p = tm_info.format[n];
541da2e3ebdSchin string:
542da2e3ebdSchin while (cp < ep && (*cp = *p++))
543da2e3ebdSchin cp++;
544da2e3ebdSchin continue;
54534f9b3eeSRoland Mainz options:
54634f9b3eeSRoland Mainz c = '+';
54734f9b3eeSRoland Mainz i = 0;
54834f9b3eeSRoland Mainz for (;;)
54934f9b3eeSRoland Mainz {
55034f9b3eeSRoland Mainz switch (*arg++)
55134f9b3eeSRoland Mainz {
55234f9b3eeSRoland Mainz case 0:
55334f9b3eeSRoland Mainz n = 0;
55434f9b3eeSRoland Mainz break;
55534f9b3eeSRoland Mainz case '=':
55634f9b3eeSRoland Mainz i = !i;
55734f9b3eeSRoland Mainz continue;
55834f9b3eeSRoland Mainz case '+':
55934f9b3eeSRoland Mainz case '-':
56034f9b3eeSRoland Mainz case '!':
56134f9b3eeSRoland Mainz c = *(arg - 1);
56234f9b3eeSRoland Mainz continue;
56334f9b3eeSRoland Mainz case 'l':
56434f9b3eeSRoland Mainz n = TM_LEAP;
56534f9b3eeSRoland Mainz break;
56634f9b3eeSRoland Mainz case 'n':
56734f9b3eeSRoland Mainz case 's':
56834f9b3eeSRoland Mainz n = TM_SUBSECOND;
56934f9b3eeSRoland Mainz break;
57034f9b3eeSRoland Mainz case 'u':
57134f9b3eeSRoland Mainz n = TM_UTC;
57234f9b3eeSRoland Mainz break;
57334f9b3eeSRoland Mainz default:
57434f9b3eeSRoland Mainz continue;
57534f9b3eeSRoland Mainz }
57634f9b3eeSRoland Mainz if (!n)
57734f9b3eeSRoland Mainz break;
57834f9b3eeSRoland Mainz
57934f9b3eeSRoland Mainz /*
58034f9b3eeSRoland Mainz * right, the global state stinks
58134f9b3eeSRoland Mainz * but we respect its locale-like status
58234f9b3eeSRoland Mainz */
58334f9b3eeSRoland Mainz
58434f9b3eeSRoland Mainz if (c == '+')
58534f9b3eeSRoland Mainz {
58634f9b3eeSRoland Mainz if (!(flags & n))
58734f9b3eeSRoland Mainz {
58834f9b3eeSRoland Mainz flags |= n;
58934f9b3eeSRoland Mainz tm_info.flags |= n;
59034f9b3eeSRoland Mainz tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone);
59134f9b3eeSRoland Mainz if (!i)
59234f9b3eeSRoland Mainz tm_info.flags &= ~n;
59334f9b3eeSRoland Mainz }
59434f9b3eeSRoland Mainz }
59534f9b3eeSRoland Mainz else if (flags & n)
59634f9b3eeSRoland Mainz {
59734f9b3eeSRoland Mainz flags &= ~n;
59834f9b3eeSRoland Mainz tm_info.flags &= ~n;
59934f9b3eeSRoland Mainz tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone);
60034f9b3eeSRoland Mainz if (!i)
60134f9b3eeSRoland Mainz tm_info.flags |= n;
60234f9b3eeSRoland Mainz }
60334f9b3eeSRoland Mainz }
60434f9b3eeSRoland Mainz continue;
605da2e3ebdSchin push:
606da2e3ebdSchin c = 0;
607da2e3ebdSchin push_delimiter:
608da2e3ebdSchin if (sp < &stack[elementsof(stack)])
609da2e3ebdSchin {
610da2e3ebdSchin sp->format = (char*)format;
611da2e3ebdSchin format = p;
612da2e3ebdSchin sp->delimiter = delimiter;
613da2e3ebdSchin delimiter = c;
614da2e3ebdSchin sp++;
615da2e3ebdSchin }
616da2e3ebdSchin continue;
617da2e3ebdSchin }
618da2e3ebdSchin tm_info.flags = flags;
619da2e3ebdSchin if (cp >= ep)
620da2e3ebdSchin cp = ep - 1;
621da2e3ebdSchin *cp = 0;
622da2e3ebdSchin return cp;
623da2e3ebdSchin }
624