diff options
Diffstat (limited to 'src/lib/libast/tm')
36 files changed, 6715 insertions, 0 deletions
diff --git a/src/lib/libast/tm/tmdata.c b/src/lib/libast/tm/tmdata.c new file mode 100644 index 0000000..1cdaf24 --- /dev/null +++ b/src/lib/libast/tm/tmdata.c @@ -0,0 +1,288 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support readonly data + */ + +#include <ast.h> +#include <tm.h> + +/* + * default format strings -- must agree with TM_* indices + */ + +static char* format[] = +{ + "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec", + + "January", "February", "March", "April", + "May", "June", "July", "August", + "September", "October", "November", "December", + + "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat", + + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", + + "%H:%M:%S", "%m/%d/%y", "%a %b %e %T %Z %Y", + + "AM", "PM", + + "GMT", "UTC", "UCT", "CUT", + + "DST", "", "", "", + + "s", "es", "", "", + + "second", "minute", "hour", "day", + "week", "month", "year", + + "midnight", "morning", "noon", "evening", + + "yesterday", "today", "tomorrow", + + "last", "ago", "past", + "this", "now", "current", + "in", "next", "hence", + "exactly", "", "", + + "at", "on", "", "", + + "st", "nd", "rd", "th", "th", + "th", "th", "th", "th", "th", + + "", "", "", "", "", + "", "", "", "", "", + + "%a %b %e %T %Y", + "%a %b %e %T %Z %Y", + "%a %b %e %T %z %Z %Y", + "%b %e %H:%M", + "%b %e %Y", + "%I:%M:%S %p", + + "", "", "", "", "", + + "first", "", "third", "fourth", "fifth", + "sixth", "seventh", "eighth", "ninth", "tenth", + + "final", "ending", "nth", + + "work", "working", "workday", +}; + +/* + * format[] lex type classes + */ + +static unsigned char lex[] = +{ + TM_MONTH_ABBREV,TM_MONTH_ABBREV,TM_MONTH_ABBREV,TM_MONTH_ABBREV, + TM_MONTH_ABBREV,TM_MONTH_ABBREV,TM_MONTH_ABBREV,TM_MONTH_ABBREV, + TM_MONTH_ABBREV,TM_MONTH_ABBREV,TM_MONTH_ABBREV,TM_MONTH_ABBREV, + + TM_MONTH, TM_MONTH, TM_MONTH, TM_MONTH, + TM_MONTH, TM_MONTH, TM_MONTH, TM_MONTH, + TM_MONTH, TM_MONTH, TM_MONTH, TM_MONTH, + + TM_DAY_ABBREV, TM_DAY_ABBREV, TM_DAY_ABBREV, TM_DAY_ABBREV, + TM_DAY_ABBREV, TM_DAY_ABBREV, TM_DAY_ABBREV, + + TM_DAY, TM_DAY, TM_DAY, TM_DAY, + TM_DAY, TM_DAY, TM_DAY, + + 0, 0, 0, + + TM_MERIDIAN, TM_MERIDIAN, + + TM_UT, TM_UT, TM_UT, TM_UT, + TM_DT, TM_DT, TM_DT, TM_DT, + + TM_SUFFIXES, TM_SUFFIXES, TM_SUFFIXES, TM_SUFFIXES, + + TM_PARTS, TM_PARTS, TM_PARTS, TM_PARTS, + TM_PARTS, TM_PARTS, TM_PARTS, + + TM_HOURS, TM_HOURS, TM_HOURS, TM_HOURS, + + TM_DAYS, TM_DAYS, TM_DAYS, + + TM_LAST, TM_LAST, TM_LAST, + TM_THIS, TM_THIS, TM_THIS, + TM_NEXT, TM_NEXT, TM_NEXT, + TM_EXACT, TM_EXACT, TM_EXACT, + + TM_NOISE, TM_NOISE, TM_NOISE, TM_NOISE, + + TM_ORDINAL, TM_ORDINAL, TM_ORDINAL, TM_ORDINAL, TM_ORDINAL, + TM_ORDINAL, TM_ORDINAL, TM_ORDINAL, TM_ORDINAL, TM_ORDINAL, + + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + + 0, 0, 0, + 0, 0, 0, + + 0, 0, 0, 0, 0, + + TM_ORDINALS, TM_ORDINALS, TM_ORDINALS, TM_ORDINALS, TM_ORDINALS, + TM_ORDINALS, TM_ORDINALS, TM_ORDINALS, TM_ORDINALS, TM_ORDINALS, + + TM_FINAL, TM_FINAL, TM_FINAL, + + TM_WORK, TM_WORK, TM_WORK, +}; + +/* + * output format digits + */ + +static char digit[] = "0123456789"; + +/* + * number of days in month i + */ + +static short days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +/* + * sum of days in months before month i + */ + +static short sum[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; + +/* + * leap second time_t and accumulated adjustments + * (reverse order -- biased for recent dates) + * + * tl.time is the seconds since the epoch for the leap event + * + * adding: the first additional second + * subtracting: the first dissappearing second + */ + +static Tm_leap_t leap[] = +{ + 1230768023, 24, /* 2008-12-31+23:59:60-0000 */ + 1136073622, 23, /* 2005-12-31+23:59:60-0000 */ + 915148821, 22, /* 1998-12-31+23:59:60-0000 */ + 867715220, 21, /* 1997-06-30+23:59:60-0000 */ + 820454419, 20, /* 1995-12-31+23:59:60-0000 */ + 773020818, 19, /* 1994-06-30+23:59:60-0000 */ + 741484817, 18, /* 1993-06-30+23:59:60-0000 */ + 709948816, 17, /* 1992-06-30+23:59:60-0000 */ + 662688015, 16, /* 1990-12-31+23:59:60-0000 */ + 631152014, 15, /* 1989-12-31+23:59:60-0000 */ + 567993613, 14, /* 1987-12-31+23:59:60-0000 */ + 489024012, 13, /* 1985-06-30+23:59:60-0000 */ + 425865611, 12, /* 1983-06-30+23:59:60-0000 */ + 394329610, 11, /* 1982-06-30+23:59:60-0000 */ + 362793609, 10, /* 1981-06-30+23:59:60-0000 */ + 315532808, 9, /* 1979-12-31+23:59:60-0000 */ + 283996807, 8, /* 1978-12-31+23:59:60-0000 */ + 252460806, 7, /* 1977-12-31+23:59:60-0000 */ + 220924805, 6, /* 1976-12-31+23:59:60-0000 */ + 189302404, 5, /* 1975-12-31+23:59:60-0000 */ + 157766403, 4, /* 1974-12-31+23:59:60-0000 */ + 126230402, 3, /* 1973-12-31+23:59:60-0000 */ + 94694401, 2, /* 1972-12-31+23:59:60-0000 */ + 78796800, 1, /* 1972-06-30+23:59:60-0000 */ + 0, 0, /* can reference (tl+1) */ + 0, 0 +}; + +/* + * time zones + * + * the UTC entries must be first + * + * zones with the same type are contiguous with all but the + * first entry for the type having a null type + * + * tz.standard is the sentinel + */ + +static Tm_zone_t zone[] = +{ + 0, "GMT", 0, ( 0 * 60), 0, /* UTC */ + 0, "UCT", 0, ( 0 * 60), 0, /* UTC */ + 0, "UTC", 0, ( 0 * 60), 0, /* UTC */ + 0, "CUT", 0, ( 0 * 60), 0, /* UTC */ + 0, "Z", 0, ( 0 * 60), 0, /* UTC */ + "USA", "HST", 0, (10 * 60), 0, /* Hawaii */ + 0, "YST", "YDT", ( 9 * 60), TM_DST, /* Yukon */ + 0, "PST", "PDT", ( 8 * 60), TM_DST, /* Pacific */ + 0, "PST", "PPET", ( 8 * 60), TM_DST, /* Pacific pres elect */ + 0, "MST", "MDT", ( 7 * 60), TM_DST, /* Mountain */ + 0, "CST", "CDT", ( 6 * 60), TM_DST, /* Central */ + 0, "EST", "EDT", ( 5 * 60), TM_DST, /* Eastern */ + "CAN", "AST", "ADT", ( 4 * 60), TM_DST, /* Atlantic */ + 0, "NST", 0, ( 3 * 60 + 30), 0, /* Newfoundland */ + "GBR", "", "BST", ( 0 * 60), TM_DST, /* British Summer */ + "EUR", "WET", "WEST", ( 0 * 60), TM_DST, /* Western Eurpoean */ + 0, "CET", "CEST", -( 1 * 60), TM_DST, /* Central European */ + 0, "MET", "MEST", -( 1 * 60), TM_DST, /* Middle European */ + 0, "EET", "EEST", -( 2 * 60), TM_DST, /* Eastern Eurpoean */ + "ISR", "IST", "IDT", -( 3 * 60), TM_DST, /* Israel */ + "IND", "IST", 0, -( 5 * 60 + 30 ), 0, /* India */ + "CHN", "HKT", 0, -( 8 * 60), 0, /* Hong Kong */ + "KOR", "KST", "KDT", -( 8 * 60), TM_DST, /* Korea */ + "SNG", "SST", 0, -( 8 * 60), 0, /* Singapore */ + "JPN", "JST", 0, -( 9 * 60), 0, /* Japan */ + "AUS", "AWST", 0, -( 8 * 60), 0, /* Australia Western */ + 0, "WST", 0, -( 8 * 60), 0, /* Australia Western */ + 0, "ACST", 0, -( 9 * 60 + 30),TM_DST, /* Australia Central */ + 0, "CST", 0, -( 9 * 60 + 30),TM_DST, /* Australia Central */ + 0, "AEST", 0, -(10 * 60), TM_DST, /* Australia Eastern */ + 0, "EST", 0, -(10 * 60), TM_DST, /* Australia Eastern */ + "NZL", "NZST", "NZDT", -(12 * 60), TM_DST, /* New Zealand */ + 0, 0, 0, 0, 0 +}; + +/* + * 2007-03-19 move tm_data from _tm_data_ to (*_tm_datap_) + * to allow future Tm_data_t growth + * by 2009 _tm_data_ can be static + */ + +#if _BLD_ast && defined(__EXPORT__) +#define extern extern __EXPORT__ +#endif + +extern Tm_data_t _tm_data_; + +#undef extern + +Tm_data_t _tm_data_ = { format, lex, digit, days, sum, leap, zone }; + +__EXTERN__(Tm_data_t, _tm_data_); + +__EXTERN__(Tm_data_t*, _tm_datap_); + +Tm_data_t* _tm_datap_ = &_tm_data_; diff --git a/src/lib/libast/tm/tmdate.c b/src/lib/libast/tm/tmdate.c new file mode 100644 index 0000000..e7ffb79 --- /dev/null +++ b/src/lib/libast/tm/tmdate.c @@ -0,0 +1,41 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <tmx.h> + +/* + * parse date expression in s and return time_t value + * see tmxdate() for details + */ + +time_t +tmdate(const char* s, char** e, time_t* clock) +{ + return tmxsec(tmxdate(s, e, tmxclock(clock))); +} diff --git a/src/lib/libast/tm/tmequiv.c b/src/lib/libast/tm/tmequiv.c new file mode 100644 index 0000000..4ab07c9 --- /dev/null +++ b/src/lib/libast/tm/tmequiv.c @@ -0,0 +1,57 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time_t conversion support + */ + +#include <tm.h> + +/* + * use one of the 14 equivalent calendar years to determine + * daylight savings time for future years beyond the range + * of the local system (via tmxtm()) + */ + +static const short equiv[] = +{ + 2006, 2012, + 2001, 2024, + 2002, 2008, + 2003, 2020, + 2009, 2004, + 2010, 2016, + 2005, 2000, +}; + +/* + * return the circa 2000 equivalent calendar year for tm + */ + +int +tmequiv(Tm_t* tm) +{ + return tm->tm_year < (2038 - 1900) ? (tm->tm_year + 1900) : equiv[tm->tm_wday + tmisleapyear(tm->tm_year)]; +} diff --git a/src/lib/libast/tm/tmfix.c b/src/lib/libast/tm/tmfix.c new file mode 100644 index 0000000..5425a8b --- /dev/null +++ b/src/lib/libast/tm/tmfix.c @@ -0,0 +1,173 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <ast.h> +#include <tmx.h> + +#define DAYS(p) (tm_data.days[(p)->tm_mon]+((p)->tm_mon==1&&LEAP(p))) +#define LEAP(p) (tmisleapyear((p)->tm_year)) + +/* + * correct out of bounds fields in tm + * + * tm_isdst is not changed -- call tmxtm() to get that + * + * tm is the return value + */ + +Tm_t* +tmfix(register Tm_t* tm) +{ + register int n; + register int w; + Tm_t* p; + time_t t; + + /* + * check for special case that adjusts tm_wday at the end + * this happens during + * nl_langinfo() => strftime() => tmfmt() + */ + + if (w = !tm->tm_sec && !tm->tm_min && !tm->tm_mday && !tm->tm_year && !tm->tm_yday && !tm->tm_isdst) + { + tm->tm_year = 99; + tm->tm_mday = 2; + } + + /* + * adjust from shortest to longest units + */ + + if ((n = tm->tm_nsec) < 0) + { + tm->tm_sec -= (TMX_RESOLUTION - n) / TMX_RESOLUTION; + tm->tm_nsec = TMX_RESOLUTION - (-n) % TMX_RESOLUTION; + } + else if (n >= TMX_RESOLUTION) + { + tm->tm_sec += n / TMX_RESOLUTION; + tm->tm_nsec %= TMX_RESOLUTION; + } + if ((n = tm->tm_sec) < 0) + { + tm->tm_min -= (60 - n) / 60; + tm->tm_sec = 60 - (-n) % 60; + } + else if (n > (59 + TM_MAXLEAP)) + { + tm->tm_min += n / 60; + tm->tm_sec %= 60; + } + if ((n = tm->tm_min) < 0) + { + tm->tm_hour -= (60 - n) / 60; + n = tm->tm_min = 60 - (-n) % 60; + } + if (n > 59) + { + tm->tm_hour += n / 60; + tm->tm_min %= 60; + } + if ((n = tm->tm_hour) < 0) + { + tm->tm_mday -= (23 - n) / 24; + tm->tm_hour = 24 - (-n) % 24; + } + else if (n >= 24) + { + tm->tm_mday += n / 24; + tm->tm_hour %= 24; + } + if (tm->tm_mon >= 12) + { + tm->tm_year += tm->tm_mon / 12; + tm->tm_mon %= 12; + } + else if (tm->tm_mon < 0) + { + tm->tm_year--; + if ((tm->tm_mon += 12) < 0) + { + tm->tm_year += tm->tm_mon / 12; + tm->tm_mon = (-tm->tm_mon) % 12; + } + } + while (tm->tm_mday < -365) + { + tm->tm_year--; + tm->tm_mday += 365 + LEAP(tm); + } + while (tm->tm_mday > 365) + { + tm->tm_mday -= 365 + LEAP(tm); + tm->tm_year++; + } + while (tm->tm_mday < 1) + { + if (--tm->tm_mon < 0) + { + tm->tm_mon = 11; + tm->tm_year--; + } + tm->tm_mday += DAYS(tm); + } + while (tm->tm_mday > (n = DAYS(tm))) + { + tm->tm_mday -= n; + if (++tm->tm_mon > 11) + { + tm->tm_mon = 0; + tm->tm_year++; + } + } + if (w) + { + w = tm->tm_wday; + t = tmtime(tm, TM_LOCALZONE); + p = tmmake(&t); + if (w = (w - p->tm_wday)) + { + if (w < 0) + w += 7; + tm->tm_wday += w; + if ((tm->tm_mday += w) > DAYS(tm)) + tm->tm_mday -= 7; + } + } + tm->tm_yday = tm_data.sum[tm->tm_mon] + (tm->tm_mon > 1 && LEAP(tm)) + tm->tm_mday - 1; + n = tm->tm_year + 1900 - 1; + tm->tm_wday = (n + n / 4 - n / 100 + n / 400 + tm->tm_yday + 1) % 7; + + /* + * tm_isdst is adjusted by tmtime() + */ + + return tm; +} diff --git a/src/lib/libast/tm/tmfmt.c b/src/lib/libast/tm/tmfmt.c new file mode 100644 index 0000000..dda0ed0 --- /dev/null +++ b/src/lib/libast/tm/tmfmt.c @@ -0,0 +1,41 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <tmx.h> + +/* + * format date given clock into buf of length len + * see tmxfmt() for details + */ + +char* +tmfmt(char* buf, size_t len, const char* format, time_t* clock) +{ + return tmxfmt(buf, len, format, tmxclock(clock)); +} diff --git a/src/lib/libast/tm/tmform.c b/src/lib/libast/tm/tmform.c new file mode 100644 index 0000000..4b608c8 --- /dev/null +++ b/src/lib/libast/tm/tmform.c @@ -0,0 +1,44 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Bell Laboratories + * + * OBSOLETE: use tmfmt() instead + * + * time conversion support + */ + +#include <ast.h> +#include <tm.h> + +/* + * format date given clock + * end of buf is returned + */ + +char* +tmform(char* buf, const char* format, time_t* clock) +{ + return tmfmt(buf, 256, format, clock); +} diff --git a/src/lib/libast/tm/tmgoff.c b/src/lib/libast/tm/tmgoff.c new file mode 100644 index 0000000..c8c8d57 --- /dev/null +++ b/src/lib/libast/tm/tmgoff.c @@ -0,0 +1,77 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Bell Laboratories + * + * time conversion support + */ + +#include <ast.h> +#include <tm.h> +#include <ctype.h> + +/* + * return minutes offset from absolute timezone expression + * + * [[-+]hh[:mm[:ss]]] + * [-+]hhmm + * + * if e is non-null then it points to the first unrecognized char in s + * d returned if no offset in s + */ + +int +tmgoff(register const char* s, char** e, int d) +{ + register int n = d; + int east; + const char* t = s; + + if ((east = *s == '+') || *s == '-') + { + s++; + if (isdigit(*s) && isdigit(*(s + 1))) + { + n = ((*s - '0') * 10 + (*(s + 1) - '0')) * 60; + s += 2; + if (*s == ':') + s++; + if (isdigit(*s) && isdigit(*(s + 1))) + { + n += ((*s - '0') * 10 + (*(s + 1) - '0')); + s += 2; + if (*s == ':') + s++; + if (isdigit(*s) && isdigit(*(s + 1))) + s += 2; + } + if (east) + n = -n; + t = s; + } + } + if (e) + *e = (char*)t; + return n; +} diff --git a/src/lib/libast/tm/tminit.c b/src/lib/libast/tm/tminit.c new file mode 100644 index 0000000..1918861 --- /dev/null +++ b/src/lib/libast/tm/tminit.c @@ -0,0 +1,460 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <tm.h> +#include <ctype.h> +#include <namval.h> + +#include "FEATURE/tmlib" + +#ifndef tzname +# if defined(__DYNAMIC__) +# undef _dat_tzname +# define tzname __DYNAMIC__(tzname) +# else +# if !_dat_tzname +# if _dat__tzname +# undef _dat_tzname +# define _dat_tzname 1 +# define tzname _tzname +# endif +# endif +# endif +# if _dat_tzname && !defined(tzname) + extern char* tzname[]; +# endif +#endif + +#define TM_type (-1) + +static const Namval_t options[] = +{ + "adjust", TM_ADJUST, + "format", TM_DEFAULT, + "leap", TM_LEAP, + "subsecond", TM_SUBSECOND, + "type", TM_type, + "utc", TM_UTC, + 0, 0 +}; + +/* + * 2007-03-19 move tm_info from _tm_info_ to (*_tm_infop_) + * to allow future Tm_info_t growth + * by 2009 _tm_info_ can be static + */ + +#if _BLD_ast && defined(__EXPORT__) +#define extern extern __EXPORT__ +#endif + +extern Tm_info_t _tm_info_; + +#undef extern + +Tm_info_t _tm_info_ = { 0 }; + +__EXTERN__(Tm_info_t, _tm_info_); + +__EXTERN__(Tm_info_t*, _tm_infop_); + +Tm_info_t* _tm_infop_ = &_tm_info_; + +#if _tzset_environ + +static char TZ[256]; +static char* TE[2]; + +struct tm* +_tm_localtime(const time_t* t) +{ + struct tm* r; + char* e; + char** v = environ; + + if (TZ[0]) + { + if (!environ || !*environ) + environ = TE; + else + e = environ[0]; + environ[0] = TZ; + } + r = localtime(t); + if (TZ[0]) + { + if (environ != v) + environ = v; + else + environ[0] = e; + } + return r; +} + +#endif + +/* + * return minutes west of GMT for local time clock + * + * isdst will point to non-zero if DST is in effect + * this routine also kicks in the local initialization + */ + +static int +tzwest(time_t* clock, int* isdst) +{ + register struct tm* tp; + register int n; + register int m; + int h; + time_t epoch; + + /* + * convert to GMT assuming local time + */ + + if (!(tp = gmtime(clock))) + { + /* + * some systems return 0 for negative time_t + */ + + epoch = 0; + clock = &epoch; + tp = gmtime(clock); + } + n = tp->tm_yday; + h = tp->tm_hour; + m = tp->tm_min; + + /* + * tmlocaltime() handles DST and GMT offset + */ + + tp = tmlocaltime(clock); + if (n = tp->tm_yday - n) + { + if (n > 1) + n = -1; + else if (n < -1) + n = 1; + } + *isdst = tp->tm_isdst; + return (h - tp->tm_hour - n * 24) * 60 + m - tp->tm_min; +} + +/* + * stropt() option handler + */ + +static int +tmopt(void* a, const void* p, int n, const char* v) +{ + Tm_zone_t* zp; + + NoP(a); + if (p) + switch (((Namval_t*)p)->value) + { + case TM_DEFAULT: + tm_info.deformat = (n && (n = strlen(v)) > 0 && (n < 2 || v[n-2] != '%' || v[n-1] != '?')) ? strdup(v) : tm_info.format[TM_DEFAULT]; + break; + case TM_type: + tm_info.local->type = (n && *v) ? ((zp = tmtype(v, NiL)) ? zp->type : strdup(v)) : 0; + break; + default: + if (n) + tm_info.flags |= ((Namval_t*)p)->value; + else + tm_info.flags &= ~((Namval_t*)p)->value; + break; + } + return 0; +} + +/* + * initialize the local timezone + */ + +static void +tmlocal(void) +{ + register Tm_zone_t* zp; + register int n; + register char* s; + register char* e; + int i; + int m; + int isdst; + char* t; + struct tm* tp; + time_t now; + char buf[16]; + + static Tm_zone_t local; + +#if _tzset_environ + { + char** v = environ; + + if (s = getenv("TZ")) + { + sfsprintf(TZ, sizeof(TZ), "TZ=%s", s); + if (!environ || !*environ) + environ = TE; + else + e = environ[0]; + environ[0] = TZ; + } + else + { + TZ[0] = 0; + e = 0; + } +#endif +#if _lib_tzset + tzset(); +#endif +#if _tzset_environ + if (environ != v) + environ = v; + else if (e) + environ[0] = e; + } +#endif +#if _dat_tzname + local.standard = strdup(tzname[0]); + local.daylight = strdup(tzname[1]); +#endif + tmlocale(); + + /* + * tm_info.local + */ + + tm_info.zone = tm_info.local = &local; + time(&now); + n = tzwest(&now, &isdst); + + /* + * compute local DST offset by roaming + * through the last 12 months until tzwest() changes + */ + + for (i = 0; i < 12; i++) + { + now -= 31 * 24 * 60 * 60; + if ((m = tzwest(&now, &isdst)) != n) + { + if (!isdst) + { + isdst = n; + n = m; + m = isdst; + } + m -= n; + break; + } + } + local.west = n; + local.dst = m; + + /* + * now get the time zone names + */ + +#if _dat_tzname + if (tzname[0]) + { + /* + * POSIX + */ + + if (!local.standard) + local.standard = strdup(tzname[0]); + if (!local.daylight) + local.daylight = strdup(tzname[1]); + } + else +#endif + if ((s = getenv("TZNAME")) && *s && (s = strdup(s))) + { + /* + * BSD + */ + + local.standard = s; + if (s = strchr(s, ',')) + *s++ = 0; + else + s = ""; + local.daylight = s; + } + else if ((s = getenv("TZ")) && *s && *s != ':' && (s = strdup(s))) + { + /* + * POSIX style but skipped by tmlocaltime() + */ + + local.standard = s; + if (*++s && *++s && *++s) + { + *s++ = 0; + tmgoff(s, &t, 0); + for (s = t; isalpha(*t); t++); + *t = 0; + } + else + s = ""; + local.daylight = s; + } + else + { + /* + * tm_data.zone table lookup + */ + + t = 0; + for (zp = tm_data.zone; zp->standard; zp++) + { + if (zp->type) + t = zp->type; + if (zp->west == n && zp->dst == m) + { + local.type = t; + local.standard = zp->standard; + if (!(s = zp->daylight)) + { + e = (s = buf) + sizeof(buf); + s = tmpoff(s, e - s, zp->standard, 0, 0); + if (s < e - 1) + { + *s++ = ' '; + tmpoff(s, e - s, tm_info.format[TM_DT], m, TM_DST); + } + s = strdup(buf); + } + local.daylight = s; + break; + } + } + if (!zp->standard) + { + /* + * not in the table + */ + + e = (s = buf) + sizeof(buf); + s = tmpoff(s, e - s, tm_info.format[TM_UT], n, 0); + local.standard = strdup(buf); + if (s < e - 1) + { + *s++ = ' '; + tmpoff(s, e - s, tm_info.format[TM_UT], m, TM_DST); + local.daylight = strdup(buf); + } + } + } + + /* + * set the options + */ + + stropt(getenv("TM_OPTIONS"), options, sizeof(*options), tmopt, NiL); + + /* + * the time zone type is probably related to the locale + */ + + if (!local.type) + { + s = local.standard; + t = 0; + for (zp = tm_data.zone; zp->standard; zp++) + { + if (zp->type) + t = zp->type; + if (tmword(s, NiL, zp->standard, NiL, 0)) + { + local.type = t; + break; + } + } + } + + /* + * tm_info.flags + */ + + if (!(tm_info.flags & TM_ADJUST)) + { + now = (time_t)78811200; /* Jun 30 1972 23:59:60 */ + tp = tmlocaltime(&now); + if (tp->tm_sec != 60) + tm_info.flags |= TM_ADJUST; + } + if (!(tm_info.flags & TM_UTC)) + { + s = local.standard; + zp = tm_data.zone; + if (local.daylight) + zp++; + for (; !zp->type && zp->standard; zp++) + if (tmword(s, NiL, zp->standard, NiL, 0)) + { + tm_info.flags |= TM_UTC; + break; + } + } +} + +/* + * initialize tm data + */ + +void +tminit(register Tm_zone_t* zp) +{ + static uint32_t serial = ~(uint32_t)0; + + if (serial != ast.env_serial) + { + serial = ast.env_serial; + if (tm_info.local) + { + memset(tm_info.local, 0, sizeof(*tm_info.local)); + tm_info.local = 0; + } + } + if (!tm_info.local) + tmlocal(); + if (!zp) + zp = tm_info.local; + tm_info.zone = zp; +} diff --git a/src/lib/libast/tm/tmleap.c b/src/lib/libast/tm/tmleap.c new file mode 100644 index 0000000..87c2f04 --- /dev/null +++ b/src/lib/libast/tm/tmleap.c @@ -0,0 +1,41 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <tmx.h> + +/* + * return clock with leap seconds adjusted + * see tmxleap() for details + */ + +time_t +tmleap(register time_t* clock) +{ + return tmxsec(tmxleap(tmxclock(clock))); +} diff --git a/src/lib/libast/tm/tmlex.c b/src/lib/libast/tm/tmlex.c new file mode 100644 index 0000000..4bcd864 --- /dev/null +++ b/src/lib/libast/tm/tmlex.c @@ -0,0 +1,67 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Bell Laboratories + * + * time conversion support + */ + +#include <ast.h> +#include <tm.h> +#include <ctype.h> + +/* + * return the tab table index that matches s ignoring case and .'s + * tm_data.format checked if tminfo.format!=tm_data.format + * + * ntab and nsuf are the number of elements in tab and suf, + * -1 for 0 sentinel + * + * all isalpha() chars in str must match + * suf is a table of nsuf valid str suffixes + * if e is non-null then it will point to first unmatched char in str + * which will always be non-isalpha() + */ + +int +tmlex(register const char* s, char** e, char** tab, int ntab, char** suf, int nsuf) +{ + register char** p; + register char* x; + register int n; + + for (p = tab, n = ntab; n-- && (x = *p); p++) + if (*x && *x != '%' && tmword(s, e, x, suf, nsuf)) + return p - tab; + if (tm_info.format != tm_data.format && tab >= tm_info.format && tab < tm_info.format + TM_NFORM) + { + tab = tm_data.format + (tab - tm_info.format); + if (suf && tab >= tm_info.format && tab < tm_info.format + TM_NFORM) + suf = tm_data.format + (suf - tm_info.format); + for (p = tab, n = ntab; n-- && (x = *p); p++) + if (*x && *x != '%' && tmword(s, e, x, suf, nsuf)) + return p - tab; + } + return -1; +} diff --git a/src/lib/libast/tm/tmlocale.c b/src/lib/libast/tm/tmlocale.c new file mode 100644 index 0000000..98dafdb --- /dev/null +++ b/src/lib/libast/tm/tmlocale.c @@ -0,0 +1,644 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion translation support + */ + +#include <ast.h> +#include <cdt.h> +#include <iconv.h> +#include <mc.h> +#include <tm.h> +#include <ast_nl_types.h> + +#include "lclib.h" + +static struct +{ + char* format; + Lc_info_t* locale; + char null[1]; +} state; + +/* + * this is unix dadgummit + */ + +static int +standardized(Lc_info_t* li, register char** b) +{ + if ((li->lc->language->flags & (LC_debug|LC_default)) || streq(li->lc->language->code, "en")) + { + b[TM_TIME] = "%H:%M:%S"; + b[TM_DATE] = "%m/%d/%y"; + b[TM_DEFAULT] = "%a %b %e %T %Z %Y"; + return 1; + } + return 0; +} + +/* + * fix up LC_TIME data after loading + */ + +static void +fixup(Lc_info_t* li, register char** b) +{ + register char** v; + register char** e; + register int n; + + static int must[] = + { + TM_TIME, + TM_DATE, + TM_DEFAULT, + TM_MERIDIAN, + TM_UT, + TM_DT, + TM_SUFFIXES, + TM_PARTS, + TM_HOURS, + TM_DAYS, + TM_LAST, + TM_THIS, + TM_NEXT, + TM_EXACT, + TM_NOISE, + TM_ORDINAL, + TM_CTIME, + TM_DATE_1, + TM_INTERNATIONAL, + TM_RECENT, + TM_DISTANT, + TM_MERIDIAN_TIME, + TM_ORDINALS, + TM_FINAL, + TM_WORK, + }; + + standardized(li, b); + for (v = b, e = b + TM_NFORM; v < e; v++) + if (!*v) + *v = state.null; + for (n = 0; n < elementsof(must); n++) + if (!*b[must[n]]) + b[must[n]] = tm_data.format[must[n]]; + if (li->lc->flags & LC_default) + for (n = 0; n < TM_NFORM; n++) + if (!*b[n]) + b[n] = tm_data.format[n]; + if (strchr(b[TM_UT], '%')) + { + tm_info.deformat = b[TM_UT]; + for (n = TM_UT; n < TM_DT; n++) + b[n] = state.null; + } + else + tm_info.deformat = b[TM_DEFAULT]; + tm_info.format = b; + if (!(tm_info.deformat = state.format)) + tm_info.deformat = tm_info.format[TM_DEFAULT]; + li->data = (void*)b; +} + +#if _WINIX + +#include <ast_windows.h> + +typedef struct Map_s +{ + LCID native; + int local; +} Map_t; + +static const Map_t map[] = +{ + LOCALE_S1159, (TM_MERIDIAN+0), + LOCALE_S2359, (TM_MERIDIAN+1), + LOCALE_SABBREVDAYNAME1, (TM_DAY_ABBREV+1), + LOCALE_SABBREVDAYNAME2, (TM_DAY_ABBREV+2), + LOCALE_SABBREVDAYNAME3, (TM_DAY_ABBREV+3), + LOCALE_SABBREVDAYNAME4, (TM_DAY_ABBREV+4), + LOCALE_SABBREVDAYNAME5, (TM_DAY_ABBREV+5), + LOCALE_SABBREVDAYNAME6, (TM_DAY_ABBREV+6), + LOCALE_SABBREVDAYNAME7, (TM_DAY_ABBREV+0), + LOCALE_SABBREVMONTHNAME1, (TM_MONTH_ABBREV+0), + LOCALE_SABBREVMONTHNAME2, (TM_MONTH_ABBREV+1), + LOCALE_SABBREVMONTHNAME3, (TM_MONTH_ABBREV+2), + LOCALE_SABBREVMONTHNAME4, (TM_MONTH_ABBREV+3), + LOCALE_SABBREVMONTHNAME5, (TM_MONTH_ABBREV+4), + LOCALE_SABBREVMONTHNAME6, (TM_MONTH_ABBREV+5), + LOCALE_SABBREVMONTHNAME7, (TM_MONTH_ABBREV+6), + LOCALE_SABBREVMONTHNAME8, (TM_MONTH_ABBREV+7), + LOCALE_SABBREVMONTHNAME9, (TM_MONTH_ABBREV+8), + LOCALE_SABBREVMONTHNAME10, (TM_MONTH_ABBREV+9), + LOCALE_SABBREVMONTHNAME11, (TM_MONTH_ABBREV+10), + LOCALE_SABBREVMONTHNAME12, (TM_MONTH_ABBREV+11), + LOCALE_SDAYNAME1, (TM_DAY+1), + LOCALE_SDAYNAME2, (TM_DAY+2), + LOCALE_SDAYNAME3, (TM_DAY+3), + LOCALE_SDAYNAME4, (TM_DAY+4), + LOCALE_SDAYNAME5, (TM_DAY+5), + LOCALE_SDAYNAME6, (TM_DAY+6), + LOCALE_SDAYNAME7, (TM_DAY+0), + LOCALE_SMONTHNAME1, (TM_MONTH+0), + LOCALE_SMONTHNAME2, (TM_MONTH+1), + LOCALE_SMONTHNAME3, (TM_MONTH+2), + LOCALE_SMONTHNAME4, (TM_MONTH+3), + LOCALE_SMONTHNAME5, (TM_MONTH+4), + LOCALE_SMONTHNAME6, (TM_MONTH+5), + LOCALE_SMONTHNAME7, (TM_MONTH+6), + LOCALE_SMONTHNAME8, (TM_MONTH+7), + LOCALE_SMONTHNAME9, (TM_MONTH+8), + LOCALE_SMONTHNAME10, (TM_MONTH+9), + LOCALE_SMONTHNAME11, (TM_MONTH+10), + LOCALE_SMONTHNAME12, (TM_MONTH+11), +}; + +#undef extern + +/* + * convert ms word date spec w to posix strftime format f + * next char after f returned + * the caller already made sure f is big enough + */ + +static char* +word2posix(register char* f, register char* w, int alternate) +{ + register char* r; + register int c; + register int p; + register int n; + + while (*w) + { + p = 0; + r = w; + while (*++w == *r); + if ((n = w - r) > 3 && alternate) + n--; + switch (*r) + { + case 'a': + case 'A': + if (!strncasecmp(w, "am/pm", 5)) + w += 5; + else if (!strncasecmp(w, "a/p", 3)) + w += 3; + c = 'p'; + break; + case 'd': + switch (n) + { + case 1: + p = '-'; + /*FALLTHROUGH*/ + case 2: + c = 'd'; + break; + case 3: + c = 'a'; + break; + default: + c = 'A'; + break; + } + break; + case 'h': + switch (n) + { + case 1: + p = '-'; + /*FALLTHROUGH*/ + default: + c = 'I'; + break; + } + break; + case 'H': + switch (n) + { + case 1: + p = '-'; + /*FALLTHROUGH*/ + default: + c = 'H'; + break; + } + break; + case 'M': + switch (n) + { + case 1: + p = '-'; + /*FALLTHROUGH*/ + case 2: + c = 'm'; + break; + case 3: + c = 'b'; + break; + default: + c = 'B'; + break; + } + break; + case 'm': + switch (n) + { + case 1: + p = '-'; + /*FALLTHROUGH*/ + default: + c = 'M'; + break; + } + break; + case 's': + switch (n) + { + case 1: + p = '-'; + /*FALLTHROUGH*/ + default: + c = 'S'; + break; + } + break; + case 'y': + switch (n) + { + case 1: + p = '-'; + /*FALLTHROUGH*/ + case 2: + c = 'y'; + break; + default: + c = 'Y'; + break; + } + break; + case '\'': + if (n & 1) + for (w = r + 1; *w; *f++ = *w++) + if (*w == '\'') + { + w++; + break; + } + continue; + case '%': + while (r < w) + { + *f++ = *r++; + *f++ = *r++; + } + continue; + default: + while (r < w) + *f++ = *r++; + continue; + } + *f++ = '%'; + if (p) + *f++ = '-'; + *f++ = c; + } + *f++ = 0; + return f; +} + +/* + * load the native LC_TIME data for the current locale + */ + +static void +native_lc_time(Lc_info_t* li) +{ + register char* s; + register char* t; + register char** b; + register int n; + register int m; + register int i; + LCID lcid; + int nt; + int ns; + int nl; + int clock_24; + int leading_0; + char buf[256]; + + lcid = li->lc->index; + nt = 2 * GetLocaleInfo(lcid, LOCALE_STIME, 0, 0) + 7; /* HH:MM:SS */ + ns = 3 * GetLocaleInfo(lcid, LOCALE_SSHORTDATE, 0, 0); + nl = 3 * GetLocaleInfo(lcid, LOCALE_SLONGDATE, 0, 0); + n = nt + ns + nl; + for (i = 0; i < elementsof(map); i++) + n += GetLocaleInfo(lcid, map[i].native, 0, 0); + if (!(b = newof(0, char*, TM_NFORM, n))) + return; + s = (char*)(b + TM_NFORM); + for (i = 0; i < elementsof(map); i++) + { + if (!(m = GetLocaleInfo(lcid, map[i].native, s, n))) + goto bad; + b[map[i].local] = s; + s += m; + } + if (!standardized(li, b)) + { + /* + * synthesize TM_TIME format from the ms word template + */ + + if (!GetLocaleInfo(lcid, LOCALE_ITIME, buf, sizeof(buf))) + goto bad; + clock_24 = atoi(buf); + if (!GetLocaleInfo(lcid, LOCALE_ITLZERO, buf, sizeof(buf))) + goto bad; + leading_0 = atoi(buf); + if (!GetLocaleInfo(lcid, LOCALE_STIME, buf, sizeof(buf))) + goto bad; + b[TM_TIME] = s; + *s++ = '%'; + if (!leading_0) + *s++ = '-'; + *s++ = clock_24 ? 'H' : 'I'; + for (t = buf; *s = *t++; s++); + *s++ = '%'; + if (!leading_0) + *s++ = '-'; + *s++ = 'M'; + for (t = buf; *s = *t++; s++); + *s++ = '%'; + if (!leading_0) + *s++ = '-'; + *s++ = 'S'; + *s++ = 0; + + /* + * synthesize TM_DATE format + */ + + if (!GetLocaleInfo(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf))) + goto bad; + b[TM_DATE] = s; + s = word2posix(s, buf, 1); + + /* + * synthesize TM_DEFAULT format + */ + + if (!GetLocaleInfo(lcid, LOCALE_SLONGDATE, buf, sizeof(buf))) + goto bad; + b[TM_DEFAULT] = s; + s = word2posix(s, buf, 1); + strcpy(s - 1, " %X"); + } + + /* + * done + */ + + fixup(li, b); + return; + bad: + free(b); +} + +#else + +#if _lib_nl_langinfo && _hdr_langinfo + +#if _hdr_nl_types +#include <nl_types.h> +#endif + +#include <langinfo.h> + +typedef struct Map_s +{ + int native; + int local; +} Map_t; + +static const Map_t map[] = +{ + AM_STR, (TM_MERIDIAN+0), + PM_STR, (TM_MERIDIAN+1), + ABDAY_1, (TM_DAY_ABBREV+0), + ABDAY_2, (TM_DAY_ABBREV+1), + ABDAY_3, (TM_DAY_ABBREV+2), + ABDAY_4, (TM_DAY_ABBREV+3), + ABDAY_5, (TM_DAY_ABBREV+4), + ABDAY_6, (TM_DAY_ABBREV+5), + ABDAY_7, (TM_DAY_ABBREV+6), + ABMON_1, (TM_MONTH_ABBREV+0), + ABMON_2, (TM_MONTH_ABBREV+1), + ABMON_3, (TM_MONTH_ABBREV+2), + ABMON_4, (TM_MONTH_ABBREV+3), + ABMON_5, (TM_MONTH_ABBREV+4), + ABMON_6, (TM_MONTH_ABBREV+5), + ABMON_7, (TM_MONTH_ABBREV+6), + ABMON_8, (TM_MONTH_ABBREV+7), + ABMON_9, (TM_MONTH_ABBREV+8), + ABMON_10, (TM_MONTH_ABBREV+9), + ABMON_11, (TM_MONTH_ABBREV+10), + ABMON_12, (TM_MONTH_ABBREV+11), + DAY_1, (TM_DAY+0), + DAY_2, (TM_DAY+1), + DAY_3, (TM_DAY+2), + DAY_4, (TM_DAY+3), + DAY_5, (TM_DAY+4), + DAY_6, (TM_DAY+5), + DAY_7, (TM_DAY+6), + MON_1, (TM_MONTH+0), + MON_2, (TM_MONTH+1), + MON_3, (TM_MONTH+2), + MON_4, (TM_MONTH+3), + MON_5, (TM_MONTH+4), + MON_6, (TM_MONTH+5), + MON_7, (TM_MONTH+6), + MON_8, (TM_MONTH+7), + MON_9, (TM_MONTH+8), + MON_10, (TM_MONTH+9), + MON_11, (TM_MONTH+10), + MON_12, (TM_MONTH+11), +#ifdef _DATE_FMT + _DATE_FMT, TM_DEFAULT, +#else + D_T_FMT, TM_DEFAULT, +#endif + D_FMT, TM_DATE, + T_FMT, TM_TIME, +#ifdef ERA + ERA, TM_ERA, + ERA_D_T_FMT, TM_ERA_DEFAULT, + ERA_D_FMT, TM_ERA_DATE, + ERA_T_FMT, TM_ERA_TIME, +#endif +#ifdef ALT_DIGITS + ALT_DIGITS, TM_DIGITS, +#endif +}; + +static void +native_lc_time(Lc_info_t* li) +{ + register char* s; + register char* t; + register char** b; + register int n; + register int i; + + n = 0; + for (i = 0; i < elementsof(map); i++) + { + if (!(t = nl_langinfo(map[i].native))) + t = tm_data.format[map[i].local]; + n += strlen(t) + 1; + } + if (!(b = newof(0, char*, TM_NFORM, n))) + return; + s = (char*)(b + TM_NFORM); + for (i = 0; i < elementsof(map); i++) + { + b[map[i].local] = s; + if (!(t = nl_langinfo(map[i].native))) + t = tm_data.format[map[i].local]; + while (*s++ = *t++); + } + fixup(li, b); +} + +#else + +#define native_lc_time(li) ((li->data=(void*)(tm_info.format=tm_data.format)),(tm_info.deformat=tm_info.format[TM_DEFAULT])) + +#endif + +#endif + +/* + * load the LC_TIME data for the current locale + */ + +static void +load(Lc_info_t* li) +{ + register char* s; + register char** b; + register char** v; + register char** e; + unsigned char* u; + ssize_t n; + iconv_t cvt; + Sfio_t* sp; + Sfio_t* tp; + char path[PATH_MAX]; + + if (b = (char**)li->data) + { + tm_info.format = b; + if (!(tm_info.deformat = state.format)) + tm_info.deformat = tm_info.format[TM_DEFAULT]; + return; + } + tm_info.format = tm_data.format; + if (!(tm_info.deformat = state.format)) + tm_info.deformat = tm_info.format[TM_DEFAULT]; + if (mcfind(NiL, NiL, LC_TIME, 0, path, sizeof(path)) && (sp = sfopen(NiL, path, "r"))) + { + n = sfsize(sp); + tp = 0; + if (u = (unsigned char*)sfreserve(sp, 3, 1)) + { + if (u[0] == 0xef && u[1] == 0xbb && u[2] == 0xbf && (cvt = iconv_open("", "utf")) != (iconv_t)(-1)) + { + if (tp = sfstropen()) + { + sfread(sp, u, 3); + n = iconv_move(cvt, sp, tp, SF_UNBOUND, NiL); + } + iconv_close(cvt); + } + if (!tp) + sfread(sp, u, 0); + } + if (b = newof(0, char*, TM_NFORM, n + 2)) + { + v = b; + e = b + TM_NFORM; + s = (char*)e; + if (tp && memcpy(s, sfstrbase(tp), n) || !tp && sfread(sp, s, n) == n) + { + s[n] = '\n'; + while (v < e) + { + *v++ = s; + if (!(s = strchr(s, '\n'))) + break; + *s++ = 0; + } + fixup(li, b); + } + else + free(b); + } + if (tp) + sfclose(tp); + sfclose(sp); + } + else + native_lc_time(li); +} + +/* + * check that tm_info.format matches the current locale + */ + +char** +tmlocale(void) +{ + Lc_info_t* li; + + if (!tm_info.format) + { + tm_info.format = tm_data.format; + if (!tm_info.deformat) + tm_info.deformat = tm_info.format[TM_DEFAULT]; + else if (tm_info.deformat != tm_info.format[TM_DEFAULT]) + state.format = tm_info.deformat; + } + li = LCINFO(AST_LC_TIME); + if (!li->data) + load(li); + return tm_info.format; +} diff --git a/src/lib/libast/tm/tmmake.c b/src/lib/libast/tm/tmmake.c new file mode 100644 index 0000000..04e0bed --- /dev/null +++ b/src/lib/libast/tm/tmmake.c @@ -0,0 +1,41 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <tmx.h> + +/* + * return Tm_t for clock + * see tmxmake() for details + */ + +Tm_t* +tmmake(time_t* clock) +{ + return tmxmake(tmxclock(clock)); +} diff --git a/src/lib/libast/tm/tmpoff.c b/src/lib/libast/tm/tmpoff.c new file mode 100644 index 0000000..0a25704 --- /dev/null +++ b/src/lib/libast/tm/tmpoff.c @@ -0,0 +1,62 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Bell Laboratories + * + * time conversion support + */ + +#include <ast.h> +#include <tm.h> + +/* + * n is minutes west of UTC + * + * append p and SHHMM part of n to s + * where S is + or - + * + * n ignored if n==d + * end of s is returned + */ + +char* +tmpoff(register char* s, size_t z, register const char* p, register int n, int d) +{ + register char* e = s + z; + + while (s < e && (*s = *p++)) + s++; + if (n != d && s < e) + { + if (n < 0) + { + n = -n; + *s++ = '+'; + } + else + *s++ = '-'; + s += sfsprintf(s, e - s, "%02d%s%02d", n / 60, d == -24*60 ? ":" : "", n % 60); + } + return s; +} diff --git a/src/lib/libast/tm/tmscan.c b/src/lib/libast/tm/tmscan.c new file mode 100644 index 0000000..c2cda80 --- /dev/null +++ b/src/lib/libast/tm/tmscan.c @@ -0,0 +1,41 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <tmx.h> + +/* + * scan date expression in s using format + * see tmxscan() for details + */ + +time_t +tmscan(const char* s, char** e, const char* format, char** f, time_t* clock, long flags) +{ + return tmxsec(tmxscan(s, e, format, f, tmxclock(clock), flags)); +} diff --git a/src/lib/libast/tm/tmsleep.c b/src/lib/libast/tm/tmsleep.c new file mode 100644 index 0000000..3e4f84e --- /dev/null +++ b/src/lib/libast/tm/tmsleep.c @@ -0,0 +1,42 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * nanosecond resolution sleep + */ + +#include <ast.h> +#include <tm.h> +#include <tv.h> + +int +tmsleep(time_t sec, time_t nsec) +{ + Tv_t tv; + + tv.tv_sec = sec; + tv.tv_nsec = nsec; + return tvsleep(&tv, NiL); +} diff --git a/src/lib/libast/tm/tmtime.c b/src/lib/libast/tm/tmtime.c new file mode 100644 index 0000000..086dd5a --- /dev/null +++ b/src/lib/libast/tm/tmtime.c @@ -0,0 +1,41 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <tmx.h> + +/* + * convert Tm_t to time_t + * see tmxtime() for details + */ + +time_t +tmtime(register Tm_t* tm, int west) +{ + return tmxsec(tmxtime(tm, west)); +} diff --git a/src/lib/libast/tm/tmtype.c b/src/lib/libast/tm/tmtype.c new file mode 100644 index 0000000..ec45f52 --- /dev/null +++ b/src/lib/libast/tm/tmtype.c @@ -0,0 +1,57 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Bell Laboratories + * + * time conversion support + */ + +#include <ast.h> +#include <tm.h> + +/* + * return the tm_data.zone[] time zone entry for type s + * + * if e is non-null then it will point to the first + * unmatched char in s + * + * 0 returned for no match + */ + +Tm_zone_t* +tmtype(register const char* s, char** e) +{ + register Tm_zone_t* zp; + register char* t; + + tmset(tm_info.zone); + zp = tm_info.local; + do + { + if ((t = zp->type) && tmword(s, e, t, NiL, 0)) return(zp); + if (zp == tm_info.local) zp = tm_data.zone; + else zp++; + } while (zp->standard); + return(0); +} diff --git a/src/lib/libast/tm/tmweek.c b/src/lib/libast/tm/tmweek.c new file mode 100644 index 0000000..78ca98c --- /dev/null +++ b/src/lib/libast/tm/tmweek.c @@ -0,0 +1,87 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + */ + +#include <tmx.h> + +static unsigned char offset[7][3] = +{ + { 7, 6, 6 }, + { 1, 7, 7 }, + { 2, 1, 8 }, + { 3, 2, 9 }, + { 4, 3, 10}, + { 5, 4, 4 }, + { 6, 5, 5 }, +}; + +/* + * type is week type + * 0 sunday first day of week + * 1 monday first day of week + * 2 monday first day of iso week + * if week<0 then return week for tm + * if day<0 then set tm to first day of week + * otherwise set tm to day in week + * and return tm->tm_yday + */ + +int +tmweek(Tm_t* tm, int type, int week, int day) +{ + int d; + + if (week < 0) + { + if ((day = tm->tm_wday - tm->tm_yday % 7) < 0) + day += 7; + week = (tm->tm_yday + offset[day][type]) / 7; + if (type == 2) + { + if (!week) + week = (day > 0 && day < 6 || tmisleapyear(tm->tm_year - 1)) ? 53 : 52; + else if (week == 53 && (tm->tm_wday + (31 - tm->tm_mday)) < 4) + week = 1; + } + return week; + } + if (day < 0) + day = type != 0; + tm->tm_mon = 0; + tm->tm_mday = 1; + tmfix(tm); + d = tm->tm_wday; + tm->tm_mday = week * 7 - offset[d][type] + ((day || type != 2) ? day : 7); + tmfix(tm); + if (d = tm->tm_wday - day) + { + tm->tm_mday -= d; + tmfix(tm); + } + return tm->tm_yday; +} diff --git a/src/lib/libast/tm/tmword.c b/src/lib/libast/tm/tmword.c new file mode 100644 index 0000000..33ce66d --- /dev/null +++ b/src/lib/libast/tm/tmword.c @@ -0,0 +1,89 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Bell Laboratories + * + * time conversion support + */ + +#include <ast.h> +#include <tm.h> +#include <ctype.h> + +/* + * match s against t ignoring case and .'s + * + * suf is an n element table of suffixes that may trail s + * if all isalpha() chars in s match then 1 is returned + * and if e is non-null it will point to the first unmatched + * char in s, otherwise 0 is returned + */ + +int +tmword(register const char* s, char** e, register const char* t, char** suf, int n) +{ + register int c; + const char* b; + + if (*s && *t) + { + b = s; + while (c = *s++) + { + if (c != '.') + { + if (!isalpha(c) || c != *t && (islower(c) ? toupper(c) : tolower(c)) != *t) + break; + t++; + } + } + s--; + if (!isalpha(c)) + { + if (c == '_') + s++; + if (e) + *e = (char*)s; + return s > b; + } + if (!*t && s > (b + 1)) + { + b = s; + while (n-- && (t = *suf++)) + { + s = b; + while (isalpha(c = *s++) && (c == *t || (islower(c) ? toupper(c) : tolower(c)) == *t)) t++; + if (!*t && !isalpha(c)) + { + if (c != '_') + s--; + if (e) + *e = (char*)s; + return 1; + } + } + } + } + return 0; +} diff --git a/src/lib/libast/tm/tmxdate.c b/src/lib/libast/tm/tmxdate.c new file mode 100644 index 0000000..8048f7f --- /dev/null +++ b/src/lib/libast/tm/tmxdate.c @@ -0,0 +1,1745 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2012 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + * + * relative times inspired by Steve Bellovin's netnews getdate(3) + */ + +#include <tmx.h> +#include <ctype.h> +#include <debug.h> + +#define dig1(s,n) ((n)=((*(s)++)-'0')) +#define dig2(s,n) ((n)=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') +#define dig3(s,n) ((n)=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') +#define dig4(s,n) ((n)=((*(s)++)-'0')*1000,(n)+=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0') + +#undef BREAK + +#define BREAK (1<<0) +#define CCYYMMDDHHMMSS (1<<1) +#define CRON (1<<2) +#define DAY (1<<3) +#define EXACT (1<<4) +#define FINAL (1<<5) +#define HOLD (1<<6) +#define HOUR (1<<7) +#define LAST (1<<8) +#define MDAY (1<<9) +#define MINUTE (1<<10) +#define MONTH (1<<11) +#define NEXT (1<<12) +#define NSEC (1<<13) +#define ORDINAL (1<<14) +#define SECOND (1<<15) +#define THIS (1L<<16) +#define WDAY (1L<<17) +#define WORK (1L<<18) +#define YEAR (1L<<19) +#define ZONE (1L<<20) + +#define FFMT "%s%s%s%s%s%s%s|" +#define FLAGS(f) (f&EXACT)?"|EXACT":"",(f&LAST)?"|LAST":"",(f&THIS)?"|THIS":"",(f&NEXT)?"|NEXT":"",(f&ORDINAL)?"|ORDINAL":"",(f&FINAL)?"|FINAL":"",(f&WORK)?"|WORK":"" +/* + * parse cron range into set + * return: -1:error 0:* 1:some + */ + +static int +range(register char* s, char** e, char* set, int lo, int hi) +{ + int n; + int m; + int i; + char* t; + + while (isspace(*s) || *s == '_') + s++; + if (*s == '*') + { + *e = s + 1; + return 0; + } + memset(set, 0, hi + 1); + for (;;) + { + n = strtol(s, &t, 10); + if (s == t || n < lo || n > hi) + return -1; + i = 1; + if (*(s = t) == '-') + { + m = strtol(++s, &t, 10); + if (s == t || m < n || m > hi) + return -1; + if (*(s = t) == '/') + { + i = strtol(++s, &t, 10); + if (s == t || i < 1) + return -1; + s = t; + } + } + else + m = n; + for (; n <= m; n += i) + set[n] = 1; + if (*s != ',') + break; + s++; + } + *e = s; + return 1; +} + +/* + * normalize <p,q> to power of 10 u in tm + */ + +static void +powerize(Tm_t* tm, unsigned long p, unsigned long q, unsigned long u) +{ + Time_t t = p; + + while (q > u) + { + q /= 10; + t /= 10; + } + while (q < u) + { + q *= 10; + t *= 10; + } + tm->tm_nsec += (int)(t % TMX_RESOLUTION); + tm->tm_sec += (int)(t / TMX_RESOLUTION); +} + +#define K1(c1) (c1) +#define K2(c1,c2) (((c1)<<8)|(c2)) +#define K3(c1,c2,c3) (((c1)<<16)|((c2)<<8)|(c3)) +#define K4(c1,c2,c3,c4) (((c1)<<24)|((c2)<<16)|((c3)<<8)|(c4)) + +#define P_INIT(n) w = n; p = q = 0; u = (char*)s + 1 + +/* + * parse date expression in s and return Time_t value + * + * if non-null, e points to the first invalid sequence in s + * now provides default values + */ + +Time_t +tmxdate(register const char* s, char** e, Time_t now) +{ + register Tm_t* tm; + register long n; + register int w; + unsigned long set; + unsigned long state; + unsigned long flags; + Time_t fix; + char* t; + char* u; + const char* o; + const char* x; + char* last; + char* type; + int day; + int dir; + int dst; + int zone; + int c; + int f; + int i; + int j; + int k; + int l; + long m; + unsigned long p; + unsigned long q; + Tm_zone_t* zp; + Tm_t ts; + char skip[UCHAR_MAX + 1]; + + /* + * check DATEMSK first + */ + + debug((error(-1, "AHA tmxdate 2009-03-06"))); + fix = tmxscan(s, &last, NiL, &t, now, 0); + if (t && !*last) + { + if (e) + *e = last; + return fix; + } + o = s; + + reset: + + /* + * use now for defaults + */ + + tm = tmxtm(&ts, now, NiL); + tm_info.date = tm->tm_zone; + day = -1; + dir = 0; + dst = TM_DST; + set = state = 0; + type = 0; + zone = TM_LOCALZONE; + skip[0] = 0; + for (n = 1; n <= UCHAR_MAX; n++) + skip[n] = isspace(n) || strchr("_,;@=|!^()[]{}", n); + + /* + * get <weekday year month day hour minutes seconds ?[ds]t [ap]m> + */ + + again: + for (;;) + { + state &= (state & HOLD) ? ~(HOLD) : ~(EXACT|LAST|NEXT|THIS); + if ((set|state) & (YEAR|MONTH|DAY)) + skip['/'] = 1; + message((-1, "AHA#%d state=" FFMT " set=" FFMT, __LINE__, FLAGS(state), FLAGS(set))); + for (;;) + { + if (*s == '.' || *s == '-' || *s == '+') + { + if (((set|state) & (YEAR|MONTH|HOUR|MINUTE|ZONE)) == (YEAR|MONTH|HOUR|MINUTE) && (i = tmgoff(s, &t, TM_LOCALZONE)) != TM_LOCALZONE) + { + zone = i; + state |= ZONE; + if (!*(s = t)) + break; + } + else if (*s == '+') + break; + } + else if (!skip[*s]) + break; + s++; + } + if (!*(last = (char*)s)) + break; + if (*s == '#') + { + if (isdigit(*++s)) + { + now = strtoull(s, &t, 0); + sns: + if (*(s = t) == '.') + { + fix = 0; + m = 1000000000; + while (isdigit(*++s)) + fix += (*s - '0') * (m /= 10); + now = tmxsns(now, fix); + } + else if (now <= 0x7fffffff) + now = tmxsns(now, 0); + goto reset; + } + else if (*s++ == '#') + { + now = tmxtime(tm, zone); + goto reset; + } + break; + } + if ((*s == 'P' || *s == 'p') && (!isalpha(*(s + 1)) || (*(s + 1) == 'T' || *(s + 1) == 't') && !isalpha(*(s + 2)))) + { + Tm_t otm; + + /* + * iso duration + */ + + otm = *tm; + t = (char*)s; + m = 0; + P_INIT('Y'); + do + { + c = *++s; + duration_next: + switch (c) + { + case 0: + m++; + if ((char*)s > u) + { + s--; + c = '_'; + goto duration_next; + } + break; + case 'T': + case 't': + m++; + if ((char*)s > u) + { + s++; + c = 'D'; + goto duration_next; + } + continue; + case 'Y': + case 'y': + m = 0; + if (q > 1) + tm->tm_sec += (365L*24L*60L*60L) * p / q; + else + tm->tm_year += p; + P_INIT('M'); + continue; + case 'm': + if (!m) + m = 1; + /*FALLTHROUGH*/ + case 'M': + switch (*(s + 1)) + { + case 'I': + case 'i': + s++; + m = 1; + w = 'S'; + break; + case 'O': + case 'o': + s++; + m = 0; + w = 'H'; + break; + case 'S': + case 's': + s++; + m = 2; + w = 's'; + break; + } + switch (m) + { + case 0: + m = 1; + if (q > 1) + tm->tm_sec += (3042L*24L*60L*60L) * p / q / 100L; + else + tm->tm_mon += p; + break; + case 1: + m = 2; + if (q > 1) + tm->tm_sec += (60L) * p / q; + else + tm->tm_min += p; + break; + default: + if (q > 1) + powerize(tm, p, q, 1000UL); + else + tm->tm_nsec += p * 1000000L; + break; + } + P_INIT(w); + continue; + case 'W': + case 'w': + m = 0; + if (q > 1) + tm->tm_sec += (7L*24L*60L*60L) * p / q; + else + tm->tm_mday += 7 * p; + P_INIT('D'); + continue; + case 'D': + case 'd': + m = 0; + if (q > 1) + tm->tm_sec += (24L*60L*60L) * p / q; + else + tm->tm_mday += p; + P_INIT('H'); + continue; + case 'H': + case 'h': + m = 1; + if (q > 1) + tm->tm_sec += (60L*60L) * p / q; + else + tm->tm_hour += p; + P_INIT('m'); + continue; + case 'S': + case 's': + m = 2; + /*FALLTHROUGH*/ + case ' ': + case '_': + case '\n': + case '\r': + case '\t': + case '\v': + if (q > 1) + powerize(tm, p, q, 1000000000UL); + else + tm->tm_sec += p; + P_INIT('U'); + continue; + case 'U': + case 'u': + switch (*(s + 1)) + { + case 'S': + case 's': + s++; + break; + } + m = 0; + if (q > 1) + powerize(tm, p, q, 1000000UL); + else + tm->tm_nsec += p * 1000L; + P_INIT('N'); + continue; + case 'N': + case 'n': + switch (*(s + 1)) + { + case 'S': + case 's': + s++; + break; + } + m = 0; + if (q > 1) + powerize(tm, p, q, 1000000000UL); + else + tm->tm_nsec += p; + P_INIT('Y'); + continue; + case '.': + if (q) + goto exact; + q = 1; + continue; + case '-': + c = 'M'; + u = (char*)s++; + while (*++u && *u != ':') + if (*u == '-') + { + c = 'Y'; + break; + } + goto duration_next; + case ':': + c = 'm'; + u = (char*)s++; + while (*++u) + if (*u == ':') + { + c = 'H'; + break; + } + goto duration_next; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + q *= 10; + p = p * 10 + (c - '0'); + continue; + default: + exact: + *tm = otm; + s = (const char*)t + 1; + if (*t == 'p') + { + state |= HOLD|EXACT; + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS); + } + goto again; + } + break; + } while (c); + continue; + } + f = -1; + if (*s == '+') + { + while (isspace(*++s) || *s == '_'); + n = strtol(s, &t, 0); + if (w = t - s) + { + for (s = t; skip[*s]; s++); + state |= (f = n) ? NEXT : THIS; + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS); + } + else + s = last; + } + if (!(state & CRON)) + { + /* + * check for cron date + * + * min hour day-of-month month day-of-week + * + * if it's cron then determine the next time + * that satisfies the specification + * + * NOTE: the only spacing is ' '||'_'||';' + */ + + i = 0; + n = *(t = (char*)s); + for (;;) + { + if (n == '*') + n = *++s; + else if (!isdigit(n)) + break; + else + while ((n = *++s) == ',' || n == '-' || n == '/' || isdigit(n)); + if (n != ' ' && n != '_' && n != ';') + { + if (!n) + i++; + break; + } + i++; + while ((n = *++s) == ' ' || n == '_'); + } + if (i == 5) + { + Time_t tt; + char hit[60]; + char mon[13]; + char day[7]; + + state |= CRON; + flags = 0; + tm->tm_sec = 0; + tm->tm_min++; + tmfix(tm); + + /* + * minute + */ + + if ((k = range(t, &t, hit, 0, 59)) < 0) + break; + if (k && !hit[i = tm->tm_min]) + { + hit[i] = 1; + do if (++i > 59) + { + i = 0; + if (++tm->tm_hour > 59) + { + tm->tm_min = i; + tmfix(tm); + } + } while (!hit[i]); + tm->tm_min = i; + } + + /* + * hour + */ + + if ((k = range(t, &t, hit, 0, 23)) < 0) + break; + if (k && !hit[i = tm->tm_hour]) + { + hit[i] = 1; + do if (++i > 23) + { + i = 0; + if (++tm->tm_mday > 28) + { + tm->tm_hour = i; + tmfix(tm); + } + } while (!hit[i]); + tm->tm_hour = i; + } + + /* + * day of month + */ + + if ((k = range(t, &t, hit, 1, 31)) < 0) + break; + if (k) + flags |= DAY|MDAY; + + /* + * month + */ + + if ((k = range(t, &t, mon, 1, 12)) < 0) + break; + if (k) + flags |= MONTH; + else + for (i = 1; i <= 12; i++) + mon[i] = 1; + + /* + * day of week + */ + + if ((k = range(t, &t, day, 0, 6)) < 0) + break; + if (k) + flags |= WDAY; + s = t; + if (flags & (MONTH|MDAY|WDAY)) + { + fix = tmxtime(tm, zone); + tm = tmxtm(tm, fix, tm->tm_zone); + i = tm->tm_mon + 1; + j = tm->tm_mday; + k = tm->tm_wday; + for (;;) + { + if (!mon[i]) + { + if (++i > 12) + { + i = 1; + tm->tm_year++; + } + tm->tm_mon = i - 1; + tm->tm_mday = 1; + tt = tmxtime(tm, zone); + if (tt < fix) + goto done; + tm = tmxtm(tm, tt, tm->tm_zone); + i = tm->tm_mon + 1; + j = tm->tm_mday; + k = tm->tm_wday; + continue; + } + if (flags & (MDAY|WDAY)) + { + if ((flags & (MDAY|WDAY)) == (MDAY|WDAY)) + { + if (hit[j] && day[k]) + break; + } + else if ((flags & MDAY) && hit[j]) + break; + else if ((flags & WDAY) && day[k]) + break; + if (++j > 28) + { + tm->tm_mon = i - 1; + tm->tm_mday = j; + tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); + i = tm->tm_mon + 1; + j = tm->tm_mday; + k = tm->tm_wday; + } + else if ((flags & WDAY) && ++k > 6) + k = 0; + } + else if (flags & MONTH) + break; + } + tm->tm_mon = i - 1; + tm->tm_mday = j; + tm->tm_wday = k; + } + continue; + } + s = t; + } + n = -1; + if (isdigit(*s)) + { + n = strtol(s, &t, 10); + if ((w = t - s) && *t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && isdigit(*(t + 3))) + { + now = n; + goto sns; + } + if ((*t == 'T' || *t == 't') && ((set|state) & (YEAR|MONTH|DAY)) == (YEAR|MONTH) && isdigit(*(t + 1))) + t++; + u = t + (*t == '-'); + message((-1, "AHA#%d n=%d w=%d u='%c' f=%d t=\"%s\"", __LINE__, n, w, *u, f, t)); + if ((w == 2 || w == 4) && (*u == 'W' || *u == 'w') && isdigit(*(u + 1))) + { + if (w == 4) + { + if ((n -= 1900) < TM_WINDOW) + break; + } + else if (n < TM_WINDOW) + n += 100; + m = n; + n = strtol(++u, &t, 10); + if ((i = (t - u)) < 2 || i > 3) + break; + if (i == 3) + { + k = n % 10; + n /= 10; + } + else if (*t != '-') + k = 1; + else if (*++t && dig1(t, k) < 1 || k > 7) + break; + if (n < 0 || n > 53) + break; + if (k == 7) + k = 0; + tm->tm_year = m; + tmweek(tm, 2, n, k); + set |= YEAR|MONTH|DAY; + s = t; + continue; + } + else if (w == 6 || w == 8 && (n / 1000000) > 12) + { + t = (char*)s; + flags = 0; + if (w == 8 || w == 6 && *u != 'T' && *u != 't') + { + dig4(t, m); + if ((m -= 1900) < TM_WINDOW) + break; + } + else + { + dig2(t, m); + if (m < TM_WINDOW) + m += 100; + } + flags |= YEAR; + if (dig2(t, l) <= 0 || l > 12) + break; + flags |= MONTH; + if (*t != 'T' && *t != 't' || !isdigit(*++t)) + { + if (w == 6) + goto save_yymm; + if (dig2(t, k) < 1 || k > 31) + break; + flags |= DAY; + goto save_yymmdd; + } + n = strtol(s = t, &t, 0); + if ((t - s) < 2) + break; + if (dig2(s, j) > 24) + break; + if ((t - s) < 2) + { + if ((t - s) == 1 || *t++ != '-') + break; + n = strtol(s = t, &t, 0); + if ((t - s) < 2) + break; + } + if (dig2(s, i) > 59) + break; + flags |= HOUR|MINUTE; + if ((t - s) == 2) + { + if (dig2(s, n) > (59 + TM_MAXLEAP)) + break; + flags |= SECOND; + } + else if (t - s) + break; + else + n = 0; + p = 0; + if (*t == '.') + { + q = 1000000000; + while (isdigit(*++t)) + p += (*t - '0') * (q /= 10); + set |= NSEC; + } + if (n > (59 + TM_MAXLEAP)) + break; + goto save; + } + else if (f == -1 && isalpha(*t) && tmlex(t, &t, tm_info.format + TM_ORDINAL, TM_ORDINALS - TM_ORDINAL, NiL, 0) >= 0) + { + message((-1, "AHA#%d n=%d", __LINE__, n)); + ordinal: + if (n) + n--; + message((-1, "AHA#%d n=%d", __LINE__, n)); + state |= ((f = n) ? NEXT : THIS)|ORDINAL; + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS); + for (s = t; skip[*s]; s++); + if (isdigit(*s)) + { + if (n = strtol(s, &t, 10)) + n--; + s = t; + if (*s == '_') + s++; + } + else + n = -1; + dir = f; + message((-1, "AHA#%d f=%d n=%d state=" FFMT, __LINE__, f, n, FLAGS(state))); + } + else + { + for (u = t; isspace(*u); u++); + message((-1, "AHA#%d n=%d u=\"%s\"", __LINE__, n, u)); + if ((j = tmlex(u, NiL, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0 && tm_data.lex[j] == TM_PARTS) + s = u; + else + { + message((-1, "AHA#%d t=\"%s\"", __LINE__, t)); + if (!(state & (LAST|NEXT|THIS)) && ((i = t - s) == 4 && (*t == '.' && isdigit(*(t + 1)) && isdigit(*(t + 2)) && *(t + 3) != '.' || (!*t || isspace(*t) || *t == '_' || isalnum(*t)) && n >= 0 && (n % 100) < 60 && ((m = (n / 100)) < 20 || m < 24 && !((set|state) & (YEAR|MONTH|HOUR|MINUTE)))) || i > 4 && i <= 12)) + { + /* + * various { date(1) touch(1) } formats + * + * [[cc]yy[mm]]ddhhmm[.ss[.nn...]] + * [cc]yyjjj + * hhmm[.ss[.nn...]] + */ + + message((-1, "AHA#%d t=\"%s\"", __LINE__, t)); + flags = 0; + if (state & CCYYMMDDHHMMSS) + break; + state |= CCYYMMDDHHMMSS; + p = 0; + if ((i == 7 || i == 5) && (!*t || *t == 'Z' || *t == 'z')) + { + if (i == 7) + { + dig4(s, m); + if ((m -= 1900) < TM_WINDOW) + break; + } + else if (dig2(s, m) < TM_WINDOW) + m += 100; + dig3(s, k); + l = 1; + j = 0; + i = 0; + n = 0; + flags |= MONTH; + } + else if (i & 1) + break; + else + { + u = t; + if (i == 12) + { + x = s; + dig2(x, m); + if (m <= 12) + { + u -= 4; + i -= 4; + x = s + 8; + dig4(x, m); + } + else + dig4(s, m); + if (m < 1969 || m >= 3000) + break; + m -= 1900; + } + else if (i == 10) + { + x = s; + if (!dig2(x, m) || m > 12 || !dig2(x, m) || m > 31 || dig2(x, m) > 24 || dig2(x, m) > 60 || dig2(x, m) <= 60 && !(tm_info.flags & TM_DATESTYLE)) + dig2(s, m); + else + { + u -= 2; + i -= 2; + x = s + 8; + dig2(x, m); + } + if (m < TM_WINDOW) + m += 100; + } + else + m = tm->tm_year; + if ((u - s) < 8) + l = tm->tm_mon + 1; + else if (dig2(s, l) <= 0 || l > 12) + break; + else + flags |= MONTH; + if ((u - s) < 6) + k = tm->tm_mday; + else if (dig2(s, k) < 1 || k > 31) + break; + else + flags |= DAY; + if ((u - s) < 4) + break; + if (dig2(s, j) > 24) + break; + if (dig2(s, i) > 59) + break; + flags |= HOUR|MINUTE; + if ((u - s) == 2) + { + dig2(s, n); + flags |= SECOND; + } + else if (u - s) + break; + else if (*t != '.') + n = 0; + else + { + n = strtol(t + 1, &t, 10); + flags |= SECOND; + if (*t == '.') + { + q = 1000000000; + while (isdigit(*++t)) + p += (*t - '0') * (q /= 10); + set |= NSEC; + } + } + if (n > (59 + TM_MAXLEAP)) + break; + } + save: + tm->tm_hour = j; + tm->tm_min = i; + tm->tm_sec = n; + tm->tm_nsec = p; + save_yymmdd: + tm->tm_mday = k; + save_yymm: + tm->tm_mon = l - 1; + tm->tm_year = m; + s = t; + set |= flags; + continue; + } + for (s = t; skip[*s]; s++); + message((-1, "AHA#%d s=\"%s\"", __LINE__, s)); + if (*s == ':' || *s == '.' && ((set|state) & (YEAR|MONTH|DAY|HOUR)) == (YEAR|MONTH|DAY)) + { + c = *s; + if ((state & HOUR) || n > 24) + break; + while (isspace(*++s) || *s == '_'); + if (!isdigit(*s)) + break; + i = n; + n = strtol(s, &t, 10); + for (s = t; isspace(*s) || *s == '_'; s++); + if (n > 59) + break; + j = n; + m = 0; + if (*s == c) + { + while (isspace(*++s) || *s == '_'); + if (!isdigit(*s)) + break; + n = strtol(s, &t, 10); + s = t; + if (n > (59 + TM_MAXLEAP)) + break; + set |= SECOND; + while (isspace(*s)) + s++; + if (*s == '.') + { + q = 1000000000; + while (isdigit(*++s)) + m += (*s - '0') * (q /= 10); + set |= NSEC; + } + } + else + n = 0; + set |= HOUR|MINUTE; + skip[':'] = 1; + k = tm->tm_hour; + tm->tm_hour = i; + l = tm->tm_min; + tm->tm_min = j; + tm->tm_sec = n; + tm->tm_nsec = m; + while (isspace(*s)) + s++; + switch (tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_MERIDIAN, 2)) + { + case TM_MERIDIAN: + s = t; + if (i == 12) + tm->tm_hour = i = 0; + break; + case TM_MERIDIAN+1: + if (i < 12) + tm->tm_hour = i += 12; + break; + } + if (f >= 0 || (state & (LAST|NEXT))) + { + message((-1, "AHA#%d f=%d i=%d j=%d k=%d l=%d", __LINE__, f, i, j, k, l)); + state &= ~HOLD; + if (f < 0) + { + if (state & LAST) + f = -1; + else if (state & NEXT) + f = 1; + else + f = 0; + } + if (f > 0) + { + if (i > k || i == k && j > l) + f--; + } + else if (i < k || i == k && j < l) + f++; + if (f > 0) + { + tm->tm_hour += f * 24; + while (tm->tm_hour >= 24) + { + tm->tm_hour -= 24; + tm->tm_mday++; + } + } + else if (f < 0) + { + tm->tm_hour += f * 24; + while (tm->tm_hour < 24) + { + tm->tm_hour += 24; + tm->tm_mday--; + } + } + } + continue; + } + } + } + } + for (;;) + { + message((-1, "AHA#%d s=\"%s\"", __LINE__, s)); + if (*s == '-' || *s == '+') + { + if (((set|state) & (MONTH|DAY|HOUR|MINUTE)) == (MONTH|DAY|HOUR|MINUTE) || *s == '+' && (!isdigit(s[1]) || !isdigit(s[2]) || s[3] != ':' && (s[3] != '.' || ((set|state) & (YEAR|MONTH)) != (YEAR|MONTH)))) + break; + s++; + } + else if (skip[*s]) + s++; + else + break; + } + if (isalpha(*s)) + { + if (n > 0) + { + x = s; + q = *s++; + message((-1, "AHA#%d n=%d q='%c'", __LINE__, n, q)); + if (isalpha(*s)) + { + q <<= 8; + q |= *s++; + if (isalpha(*s)) + { + if (tmlex(s, &t, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES, NiL, 0) >= 0) + s = t; + if (isalpha(*s)) + { + q <<= 8; + q |= *s++; + if (isalpha(*s)) + { + q <<= 8; + q |= *s++; + if (isalpha(*s)) + q = 0; + } + } + } + } + switch (q) + { + case K1('y'): + case K1('Y'): + case K2('y','r'): + case K2('Y','R'): + tm->tm_year += n; + set |= YEAR; + continue; + case K1('M'): + case K2('m','o'): + case K2('M','O'): + tm->tm_mon += n; + set |= MONTH; + continue; + case K1('w'): + case K1('W'): + case K2('w','k'): + case K2('W','K'): + tm->tm_mday += n * 7; + set |= DAY; + continue; + case K1('d'): + case K1('D'): + case K2('d','a'): + case K2('d','y'): + case K2('D','A'): + case K2('D','Y'): + tm->tm_mday += n; + set |= DAY; + continue; + case K1('h'): + case K1('H'): + case K2('h','r'): + case K2('H','R'): + tm->tm_hour += n; + set |= HOUR; + continue; + case K1('m'): + case K2('m','n'): + case K2('M','N'): + tm->tm_min += n; + set |= MINUTE; + continue; + case K1('s'): + case K2('s','c'): + case K1('S'): + case K2('S','C'): + tm->tm_sec += n; + set |= SECOND; + continue; + case K2('m','s'): + case K3('m','s','c'): + case K4('m','s','e','c'): + case K2('M','S'): + case K3('M','S','C'): + case K4('M','S','E','C'): + tm->tm_nsec += n * 1000000L; + continue; + case K1('u'): + case K2('u','s'): + case K3('u','s','c'): + case K4('u','s','e','c'): + case K1('U'): + case K2('U','S'): + case K3('U','S','C'): + case K4('U','S','E','C'): + tm->tm_nsec += n * 1000L; + continue; + case K2('n','s'): + case K3('n','s','c'): + case K4('n','s','e','c'): + case K2('N','S'): + case K3('N','S','C'): + case K4('N','S','E','C'): + tm->tm_nsec += n; + continue; + } + s = x; + } + if ((j = tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0) + { + if (tm_data.lex[j] == TM_PARTS || n < 1000) + { + s = t; + switch (tm_data.lex[j]) + { + case TM_EXACT: + state |= HOLD|EXACT; + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS); + continue; + case TM_LAST: + state |= HOLD|LAST; + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS); + continue; + case TM_THIS: + state |= HOLD|THIS; + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS); + n = 0; + continue; + case TM_NEXT: + /* + * disambiguate english "last ... in" + */ + + if (!((state|set) & LAST)) + { + state |= HOLD|NEXT; + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS); + continue; + } + /*FALLTHROUGH*/ + case TM_FINAL: + state |= HOLD|THIS|FINAL; + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS|FINAL); + continue; + case TM_WORK: + message((-1, "AHA#%d WORK", __LINE__)); + state |= WORK; + set |= DAY; + if (state & LAST) + { + state &= ~LAST; + set &= ~LAST; + state |= FINAL; + set |= FINAL; + } + goto clear_hour; + case TM_ORDINAL: + j += TM_ORDINALS - TM_ORDINAL; + message((-1, "AHA#%d j=%d", __LINE__, j)); + /*FALLTHROUGH*/ + case TM_ORDINALS: + n = j - TM_ORDINALS + 1; + message((-1, "AHA#%d n=%d", __LINE__, n)); + goto ordinal; + case TM_MERIDIAN: + if (f >= 0) + f++; + else if (state & LAST) + f = -1; + else if (state & THIS) + f = 1; + else if (state & NEXT) + f = 2; + else + f = 0; + if (n > 0) + { + if (n > 24) + goto done; + tm->tm_hour = n; + } + for (k = tm->tm_hour; k < 0; k += 24); + k %= 24; + if (j == TM_MERIDIAN) + { + if (k == 12) + tm->tm_hour -= 12; + } + else if (k < 12) + tm->tm_hour += 12; + if (n > 0) + goto clear_min; + continue; + case TM_DAY_ABBREV: + j += TM_DAY - TM_DAY_ABBREV; + /*FALLTHROUGH*/ + case TM_DAY: + case TM_PARTS: + case TM_HOURS: + state |= set & (EXACT|LAST|NEXT|THIS); + if (!(state & (LAST|NEXT|THIS))) + for (;;) + { + while (skip[*s]) + s++; + if ((k = tmlex(s, &t, tm_info.format + TM_LAST, TM_NOISE - TM_LAST, NiL, 0)) >= 0) + { + s = t; + if (k <= 2) + state |= LAST; + else if (k <= 5) + state |= THIS; + else if (k <= 8) + state |= NEXT; + else + state |= EXACT; + } + else + { + state |= (n > 0) ? NEXT : THIS; + break; + } + set &= ~(EXACT|LAST|NEXT|THIS); + set |= state & (EXACT|LAST|NEXT|THIS); + } + /*FALLTHROUGH*/ + case TM_DAYS: + message((-1, "AHA#%d n=%d j=%d f=%d state=" FFMT, __LINE__, n, j, f, FLAGS(state))); + if (n == -1) + { + /* + * disambiguate english "second" + */ + + if (j == TM_PARTS && f == -1) + { + state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ + n = 2; + goto ordinal; + } + n = 1; + } + + /* + * disambiguate "last" vs. { "previous" "final" } + */ + + while (isspace(*s)) + s++; + message((-1, "AHA#%d disambiguate LAST s='%s'", __LINE__, s)); + if ((k = tmlex(s, &t, tm_info.format + TM_NEXT, TM_EXACT - TM_NEXT, NiL, 0)) >= 0 || (k = tmlex(s, &t, tm_info.format + TM_PARTS + 3, 1, NiL, 0)) >= 0) + { + s = t; + if (state & LAST) + { + state &= ~LAST; + set &= ~LAST; + state |= FINAL; + set |= FINAL; + message((-1, "AHA#%d LAST => FINAL", __LINE__)); + } + else + state &= ~(THIS|NEXT); + } + message((-1, "AHA#%d disambiguate LAST k=%d", __LINE__, k)); + if (state & LAST) + n = -n; + else if (!(state & NEXT)) + n--; + m = (f > 0) ? f * n : n; + message((-1, "AHA#%d f=%d n=%d i=%d j=%d k=%d l=%d m=%d state=" FFMT, __LINE__, f, n, i, j, k, l, m, FLAGS(state))); + switch (j) + { + case TM_DAYS+0: + tm->tm_mday--; + set |= DAY; + goto clear_hour; + case TM_DAYS+1: + set |= DAY; + goto clear_hour; + case TM_DAYS+2: + tm->tm_mday++; + set |= DAY; + goto clear_hour; + case TM_PARTS+0: + set |= SECOND; + if ((m < 0 ? -m : m) > (365L*24L*60L*60L)) + { + now = tmxtime(tm, zone) + tmxsns(m, 0); + goto reset; + } + tm->tm_sec += m; + goto clear_nsec; + case TM_PARTS+1: + tm->tm_min += m; + set |= MINUTE; + goto clear_sec; + case TM_PARTS+2: + tm->tm_hour += m; + set |= MINUTE; + goto clear_min; + case TM_PARTS+3: + message((-1, "AHA#%d DAY m=%d n=%d%s", __LINE__, m, n, (state & LAST) ? " LAST" : "")); + if ((state & (LAST|NEXT|THIS)) == LAST) + tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); + else if (state & ORDINAL) + tm->tm_mday = m + 1; + else + tm->tm_mday += m; + if (!(set & (FINAL|WORK))) + set |= HOUR; + goto clear_hour; + case TM_PARTS+4: + tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); + tm->tm_mday += 7 * m - tm->tm_wday + 1; + set |= DAY; + goto clear_hour; + case TM_PARTS+5: + tm->tm_mon += m; + set |= MONTH; + goto clear_mday; + case TM_PARTS+6: + tm->tm_year += m; + goto clear_mon; + case TM_HOURS+0: + tm->tm_mday += m; + set |= DAY; + goto clear_hour; + case TM_HOURS+1: + tm->tm_mday += m; + tm->tm_hour = 6; + set |= HOUR; + goto clear_min; + case TM_HOURS+2: + tm->tm_mday += m; + tm->tm_hour = 12; + set |= HOUR; + goto clear_min; + case TM_HOURS+3: + tm->tm_mday += m; + tm->tm_hour = 18; + set |= HOUR; + goto clear_min; + } + if (m >= 0 && (state & ORDINAL)) + tm->tm_mday = 1; + tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); + day = j -= TM_DAY; + if (!dir) + dir = m; + message((-1, "AHA#%d j=%d m=%d", __LINE__, j, m)); + j -= tm->tm_wday; + message((-1, "AHA#%d mday=%d wday=%d day=%d dir=%d f=%d i=%d j=%d l=%d m=%d", __LINE__, tm->tm_mday, tm->tm_wday, day, dir, f, i, j, l, m)); + if (state & (LAST|NEXT|THIS)) + { + if (state & ORDINAL) + { + while (isspace(*s)) + s++; + if (isdigit(*s) || tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0) >= 0) + { + state &= ~(LAST|NEXT|THIS); + goto clear_hour; + } + } + if (j < 0) + j += 7; + } + else if (j > 0) + j -= 7; + message((-1, "AHA#%d day=%d mday=%d f=%d m=%d j=%d state=" FFMT, __LINE__, day, tm->tm_mday, f, m, j, FLAGS(state))); + set |= DAY; + if (set & (FINAL|WORK)) + goto clear_hour; + else if (state & (LAST|NEXT|THIS)) + { + if (f >= 0) + day = -1; + else if (m > 0 && (state & (NEXT|YEAR|MONTH)) == NEXT && j >= 0) + m--; + tm->tm_mday += j + m * 7; + set &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ + state &= ~(LAST|NEXT|THIS|ORDINAL); /*AHA*/ + if (!(state & EXACT)) + goto clear_hour; + } + continue; + case TM_MONTH_ABBREV: + j += TM_MONTH - TM_MONTH_ABBREV; + /*FALLTHROUGH*/ + case TM_MONTH: + if (state & MONTH) + goto done; + state |= MONTH; + i = tm->tm_mon; + tm->tm_mon = j - TM_MONTH; + if (n < 0) + { + while (skip[*s]) + s++; + if (isdigit(*s)) + { + n = strtol(s, &t, 10); + if (n <= 31 && *t != ':') + s = t; + else + n = -1; + } + } + if (n >= 0) + { + if (n > 31) + goto done; + state |= DAY|MDAY; + tm->tm_mday = n; + if (f > 0) + tm->tm_year += f; + } + if (state & (LAST|NEXT|THIS)) + { + n = i; + goto rel_month; + } + continue; + case TM_UT: + if (state & ZONE) + goto done; + state |= ZONE; + zone = tmgoff(s, &t, 0); + s = t; + continue; + case TM_DT: + if (!dst) + goto done; + if (!(state & ZONE)) + { + dst = tm->tm_zone->dst; + zone = tm->tm_zone->west; + } + zone += tmgoff(s, &t, dst); + s = t; + dst = 0; + state |= ZONE; + continue; + case TM_NOISE: + continue; + } + } + } + if (n < 1000) + { + if (!(state & ZONE) && (zp = tmzone(s, &t, type, &dst))) + { + s = t; + zone = zp->west + dst; + tm_info.date = zp; + state |= ZONE; + if (n < 0) + continue; + } + else if (!type && (zp = tmtype(s, &t))) + { + s = t; + type = zp->type; + if (n < 0) + continue; + } + state |= BREAK; + } + } + else if (*s == '/') + { + if (!(state & (YEAR|MONTH)) && n >= 1969 && n < 3000 && (i = strtol(s + 1, &t, 10)) > 0 && i <= 12) + { + state |= YEAR; + tm->tm_year = n - 1900; + s = t; + i--; + } + else + { + if ((state & MONTH) || n <= 0 || n > 31) + break; + if (isalpha(*++s)) + { + if ((i = tmlex(s, &t, tm_info.format, TM_DAY_ABBREV, NiL, 0)) < 0) + break; + if (i >= TM_MONTH) + i -= TM_MONTH; + s = t; + } + else + { + i = n - 1; + n = strtol(s, &t, 10); + s = t; + if (n <= 0 || n > 31) + break; + if (*s == '/' && !isdigit(*(s + 1))) + break; + } + state |= DAY; + tm->tm_mday = n; + } + state |= MONTH; + n = tm->tm_mon; + tm->tm_mon = i; + if (*s == '/') + { + n = strtol(++s, &t, 10); + w = t - s; + s = t; + if (*s == '/' || *s == ':' || *s == '-' || *s == '_') + s++; + } + else + { + if (state & (LAST|NEXT|THIS)) + { + rel_month: + if (state & LAST) + tm->tm_year -= (tm->tm_mon < n) ? 0 : 1; + else + tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0); + if (state & MDAY) + goto clear_hour; + set &= ~(LAST|NEXT|THIS); /*AHA*/ + state &= ~(LAST|NEXT|THIS); /*AHA*/ + goto clear_mday; + } + continue; + } + } + if (n < 0 || w > 4) + break; + if (w == 4) + { + if ((state & YEAR) || n < 1969 || n >= 3000) + break; + state |= YEAR; + tm->tm_year = n - 1900; + } + else if (w == 3) + { + if (state & (MONTH|MDAY|WDAY)) + break; + state |= MONTH|DAY|MDAY; + tm->tm_mon = 0; + tm->tm_mday = n; + } + else if (w == 2 && !(state & YEAR)) + { + state |= YEAR; + if (n < TM_WINDOW) + n += 100; + tm->tm_year = n; + } + else if (!(state & MONTH) && n >= 1 && n <= 12) + { + state |= MONTH; + tm->tm_mon = n - 1; + } + else if (!(state & (MDAY|WDAY)) && n >= 1 && n <= 31) + { + state |= DAY|MDAY|WDAY; + tm->tm_mday = n; + } + else + break; + if (state & BREAK) + { + last = t; + break; + } + continue; + clear_mon: + if ((set|state) & (EXACT|MONTH)) + continue; + tm->tm_mon = 0; + clear_mday: + set |= MONTH; + if ((set|state) & (EXACT|DAY|HOUR)) + continue; + tm->tm_mday = 1; + clear_hour: + message((-1, "AHA#%d DAY", __LINE__)); + set |= DAY; + if ((set|state) & (EXACT|HOUR)) + continue; + tm->tm_hour = 0; + clear_min: + set |= HOUR; + if ((set|state) & (EXACT|MINUTE)) + continue; + tm->tm_min = 0; + clear_sec: + set |= MINUTE; + if ((set|state) & (EXACT|SECOND)) + continue; + tm->tm_sec = 0; + clear_nsec: + set |= SECOND; + if ((set|state) & (EXACT|NSEC)) + continue; + tm->tm_nsec = 0; + } + done: + if (day >= 0 && !(state & (MDAY|WDAY))) + { + message((-1, "AHA#%d day=%d dir=%d state=" FFMT, __LINE__, day, dir, FLAGS(state))); + tmfix(tm); + m = dir; + if (state & MONTH) + tm->tm_mday = 1; + else if (m < 0) + m++; + tm = tmxtm(tm, tmxtime(tm, zone), tm->tm_zone); + j = day - tm->tm_wday; + if (j < 0) + j += 7; + tm->tm_mday += j + m * 7; + if (state & FINAL) + for (n = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); (tm->tm_mday + 7) <= n; tm->tm_mday += 7); + } + else if (day < 0 && (state & FINAL) && (set & DAY)) + { + tmfix(tm); + tm->tm_mday = tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)); + } + if (state & WORK) + { + tm->tm_mday = (set & FINAL) ? (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year))) : 1; + tmfix(tm); + message((-1, "AHA#%d WORK mday=%d wday=%d", __LINE__, tm->tm_mday, tm->tm_wday)); + if (tm->tm_wday == 0 && (j = 1) || tm->tm_wday == 6 && (j = 2)) + { + if ((tm->tm_mday + j) > (tm_data.days[tm->tm_mon] + (tm->tm_mon == 1 && tmisleapyear(tm->tm_year)))) + j -= 3; + tm->tm_mday += j; + } + } + now = tmxtime(tm, zone); + if (tm->tm_year <= 70 && tmxsec(now) > 31536000) + { + now = 0; + last = (char*)o; + } + if (e) + *e = last; + return now; +} diff --git a/src/lib/libast/tm/tmxduration.c b/src/lib/libast/tm/tmxduration.c new file mode 100644 index 0000000..eb456a9 --- /dev/null +++ b/src/lib/libast/tm/tmxduration.c @@ -0,0 +1,80 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped + +#include <tmx.h> +#include <ctype.h> + +/* + * parse duration expression in s and return Time_t value + * if non-null, e points to the first unused char in s + * returns 0 with *e==s on error + */ + +Time_t +tmxduration(const char* s, char** e) +{ + Time_t ns; + Time_t ts; + Time_t now; + char* last; + char* t; + char* x; + Sfio_t* f; + int i; + + now = TMX_NOW; + while (isspace(*s)) + s++; + if (*s == 'P' || *s == 'p') + ns = tmxdate(s, &last, now) - now; + else + { + ns = strtod(s, &last) * TMX_RESOLUTION; + if (*last && (f = sfstropen())) + { + sfprintf(f, "exact %s", s); + t = sfstruse(f); + ts = tmxdate(t, &x, now); + if ((i = x - t - 6) > (last - s)) + { + last = (char*)s + i; + ns = ts - now; + } + else + { + sfprintf(f, "p%s", s); + t = sfstruse(f); + ts = tmxdate(t, &x, now); + if ((i = x - t - 1) > (last - s)) + { + last = (char*)s + i; + ns = ts - now; + } + } + sfstrclose(f); + } + } + if (e) + *e = last; + return ns; +} diff --git a/src/lib/libast/tm/tmxfmt.c b/src/lib/libast/tm/tmxfmt.c new file mode 100644 index 0000000..2010c08 --- /dev/null +++ b/src/lib/libast/tm/tmxfmt.c @@ -0,0 +1,703 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + */ + +#include <tmx.h> +#include <ctype.h> + +#define warped(t,n) ((t)<((n)-tmxsns(6L*30L*24L*60L*60L,0))||(t)>((n)+tmxsns(24L*60L*60L,0))) + +/* + * format n with padding p into s + * return end of s + * + * p: <0 blank padding + * 0 no padding + * >0 0 padding + */ + +static char* +number(register char* s, register char* e, register long n, register int p, int w, int pad) +{ + char* b; + + if (w) + { + if (p > 0 && (pad == 0 || pad == '0')) + while (w > p) + { + p++; + n *= 10; + } + else if (w > p) + p = w; + } + switch (pad) + { + case '-': + p = 0; + break; + case '_': + if (p > 0) + p = -p; + break; + case '0': + if (p < 0) + p = -p; + break; + } + b = s; + if (p > 0) + s += sfsprintf(s, e - s, "%0*lu", p, n); + else if (p < 0) + s += sfsprintf(s, e - s, "%*lu", -p, n); + else + s += sfsprintf(s, e - s, "%lu", n); + if (w && (s - b) > w) + *(s = b + w) = 0; + return s; +} + +typedef struct Stack_s +{ + char* format; + int delimiter; +} Stack_t; + +/* + * format t into buf of length len + * end of buf is returned + */ + +char* +tmxfmt(char* buf, size_t len, const char* format, Time_t t) +{ + register char* cp; + register char* ep; + register char* p; + register int n; + int c; + int i; + int flags; + int alt; + int pad; + int delimiter; + int width; + int prec; + int parts; + char* arg; + char* f; + const char* oformat; + Tm_t* tm; + Tm_zone_t* zp; + Time_t now; + Stack_t* sp; + Stack_t stack[8]; + Tm_t ts; + char argbuf[256]; + char fmt[32]; + + tmlocale(); + tm = tmxtm(&ts, t, NiL); + if (!format || !*format) + format = tm_info.deformat; + oformat = format; + flags = tm_info.flags; + sp = &stack[0]; + cp = buf; + ep = buf + len; + delimiter = 0; + for (;;) + { + if ((c = *format++) == delimiter) + { + delimiter = 0; + if (sp <= &stack[0]) + break; + sp--; + format = sp->format; + delimiter = sp->delimiter; + continue; + } + if (c != '%') + { + if (cp < ep) + *cp++ = c; + continue; + } + alt = 0; + arg = 0; + pad = 0; + width = 0; + prec = 0; + parts = 0; + for (;;) + { + switch (c = *format++) + { + case '_': + case '-': + pad = c; + continue; + case 'E': + case 'O': + if (!isalpha(*format)) + break; + alt = c; + continue; + case '0': + if (!parts) + { + pad = c; + continue; + } + /*FALLTHROUGH*/ + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + switch (parts) + { + case 0: + parts++; + /*FALLTHROUGH*/ + case 1: + width = width * 10 + (c - '0'); + break; + case 2: + prec = prec * 10 + (c - '0'); + break; + } + continue; + case '.': + if (!parts++) + parts++; + continue; + case '(': + i = 1; + arg = argbuf; + for (;;) + { + if (!(c = *format++)) + { + format--; + break; + } + else if (c == '(') + i++; + else if (c == ')' && !--i) + break; + else if (arg < &argbuf[sizeof(argbuf) - 1]) + *arg++ = c; + } + *arg = 0; + arg = argbuf; + continue; + default: + break; + } + break; + } + switch (c) + { + case 0: + format--; + continue; + case '%': + if (cp < ep) + *cp++ = '%'; + continue; + case '?': + if (tm_info.deformat != tm_info.format[TM_DEFAULT]) + format = tm_info.deformat; + else if (!*format) + format = tm_info.format[TM_DEFAULT]; + continue; + case 'a': /* abbreviated day of week name */ + n = TM_DAY_ABBREV + tm->tm_wday; + goto index; + case 'A': /* day of week name */ + n = TM_DAY + tm->tm_wday; + goto index; + case 'b': /* abbreviated month name */ + case 'h': + n = TM_MONTH_ABBREV + tm->tm_mon; + goto index; + case 'B': /* month name */ + n = TM_MONTH + tm->tm_mon; + goto index; + case 'c': /* `ctime(3)' date sans newline */ + p = tm_info.format[TM_CTIME]; + goto push; + case 'C': /* 2 digit century */ + cp = number(cp, ep, (long)(1900 + tm->tm_year) / 100, 2, width, pad); + continue; + case 'd': /* day of month */ + cp = number(cp, ep, (long)tm->tm_mday, 2, width, pad); + continue; + case 'D': /* date */ + p = tm_info.format[TM_DATE]; + goto push; + case 'e': /* blank padded day of month */ + cp = number(cp, ep, (long)tm->tm_mday, -2, width, pad); + continue; + case 'f': /* (AST) OBSOLETE use %Qf */ + p = "%Qf"; + goto push; + case 'F': /* ISO 8601:2000 standard date format */ + p = "%Y-%m-%d"; + goto push; + case 'g': /* %V 2 digit year */ + case 'G': /* %V 4 digit year */ + n = tm->tm_year + 1900; + if (tm->tm_yday < 7) + { + if (tmweek(tm, 2, -1, -1) >= 52) + n--; + } + else if (tm->tm_yday > 358) + { + if (tmweek(tm, 2, -1, -1) <= 1) + n++; + } + if (c == 'g') + { + n %= 100; + c = 2; + } + else + c = 4; + cp = number(cp, ep, (long)n, c, width, pad); + continue; + case 'H': /* hour (0 - 23) */ + cp = number(cp, ep, (long)tm->tm_hour, 2, width, pad); + continue; + case 'i': /* (AST) OBSOLETE use %QI */ + p = "%QI"; + goto push; + case 'I': /* hour (0 - 12) */ + if ((n = tm->tm_hour) > 12) n -= 12; + else if (n == 0) n = 12; + cp = number(cp, ep, (long)n, 2, width, pad); + continue; + case 'j': /* Julian date (1 offset) */ + cp = number(cp, ep, (long)(tm->tm_yday + 1), 3, width, pad); + continue; + case 'J': /* Julian date (0 offset) */ + cp = number(cp, ep, (long)tm->tm_yday, 3, width, pad); + continue; + case 'k': /* (AST) OBSOLETE use %QD */ + p = "%QD"; + goto push; + case 'K': /* (AST) largest to smallest */ + switch (alt) + { + case 'E': + p = (pad == '_') ? "%Y-%m-%d %H:%M:%S.%N %z" : "%Y-%m-%d+%H:%M:%S.%N%z"; + break; + case 'O': + p = (pad == '_') ? "%Y-%m-%d %H:%M:%S.%N" : "%Y-%m-%d+%H:%M:%S.%N"; + break; + default: + p = (pad == '_') ? "%Y-%m-%d %H:%M:%S" : "%Y-%m-%d+%H:%M:%S"; + break; + } + goto push; + case 'l': /* (AST) OBSOLETE use %QL */ + p = "%QL"; + goto push; + case 'L': /* (AST) OBSOLETE use %Ql */ + p = "%Ql"; + goto push; + case 'm': /* month number */ + cp = number(cp, ep, (long)(tm->tm_mon + 1), 2, width, pad); + continue; + case 'M': /* minutes */ + cp = number(cp, ep, (long)tm->tm_min, 2, width, pad); + continue; + case 'n': + if (cp < ep) + *cp++ = '\n'; + continue; + case 'N': /* (AST|GNU) nanosecond part */ + cp = number(cp, ep, (long)tm->tm_nsec, 9, width, pad); + continue; +#if 0 + case 'o': /* (UNUSED) */ + continue; +#endif + case 'p': /* meridian */ + n = TM_MERIDIAN + (tm->tm_hour >= 12); + goto index; + case 'P': /* (AST|GNU) lower case meridian */ + p = tm_info.format[TM_MERIDIAN + (tm->tm_hour >= 12)]; + while (cp < ep && (n = *p++)) + *cp++ = isupper(n) ? tolower(n) : n; + continue; + case 'q': /* (AST) OBSOLETE use %Qz */ + p = "%Qz"; + goto push; + case 'Q': /* (AST) %Q<alpha> or %Q<delim>recent<delim>distant<delim> */ + if (c = *format) + { + format++; + if (isalpha(c)) + { + switch (c) + { + case 'd': /* `ls -l' distant date */ + p = tm_info.format[TM_DISTANT]; + goto push; + case 'D': /* `date(1)' date */ + p = tm_info.format[TM_DATE_1]; + goto push; + case 'f': /* TM_DEFAULT override */ + p = tm_info.deformat; + goto push; + case 'I': /* international `date(1)' date */ + p = tm_info.format[TM_INTERNATIONAL]; + goto push; + case 'l': /* TM_DEFAULT */ + p = tm_info.format[TM_DEFAULT]; + goto push; + case 'L': /* `ls -l' date */ + if (t) + { + now = tmxgettime(); + if (warped(t, now)) + { + p = tm_info.format[TM_DISTANT]; + goto push; + } + } + p = tm_info.format[TM_RECENT]; + goto push; + case 'o': /* set options ( %([+-]flag...)o ) */ + if (arg) + { + c = '+'; + i = 0; + for (;;) + { + switch (*arg++) + { + case 0: + n = 0; + break; + case '=': + i = !i; + continue; + case '+': + case '-': + case '!': + c = *(arg - 1); + continue; + case 'l': + n = TM_LEAP; + break; + case 'n': + case 's': + n = TM_SUBSECOND; + break; + case 'u': + n = TM_UTC; + break; + default: + continue; + } + if (!n) + break; + + /* + * right, the global state stinks + * but we respect its locale-like status + */ + + if (c == '+') + { + if (!(flags & n)) + { + flags |= n; + tm_info.flags |= n; + tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone); + if (!i) + tm_info.flags &= ~n; + } + } + else if (flags & n) + { + flags &= ~n; + tm_info.flags &= ~n; + tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone); + if (!i) + tm_info.flags |= n; + } + } + } + break; + case 'r': /* `ls -l' recent date */ + p = tm_info.format[TM_RECENT]; + goto push; + case 'z': /* time zone nation code */ + if (!(flags & TM_UTC)) + { + if ((zp = tm->tm_zone) != tm_info.local) + for (; zp >= tm_data.zone; zp--) + if (p = zp->type) + goto string; + else if (p = zp->type) + goto string; + } + break; + default: + format--; + break; + } + } + else + { + if (t) + { + now = tmxgettime(); + p = warped(t, now) ? (char*)0 : (char*)format; + } + else + p = (char*)format; + i = 0; + while (n = *format) + { + format++; + if (n == c) + { + if (!p) + p = (char*)format; + if (++i == 2) + goto push_delimiter; + } + } + } + } + continue; + case 'r': + p = tm_info.format[TM_MERIDIAN_TIME]; + goto push; + case 'R': + p = "%H:%M"; + goto push; + case 's': /* (DEFACTO) seconds[.nanoseconds] since the epoch */ + case '#': + now = t; + f = fmt; + *f++ = '%'; + if (pad == '0') + *f++ = pad; + if (width) + f += sfsprintf(f, &fmt[sizeof(fmt)] - f, "%d", width); + f += sfsprintf(f, &fmt[sizeof(fmt)] - f, "I%du", sizeof(Tmxsec_t)); + cp += sfsprintf(cp, ep - cp, fmt, tmxsec(now)); + if (parts > 1) + { + n = sfsprintf(cp, ep - cp, ".%09I*u", sizeof(Tmxnsec_t), tmxnsec(now)); + if (prec && n >= prec) + n = prec + 1; + cp += n; + } + continue; + case 'S': /* seconds */ + cp = number(cp, ep, (long)tm->tm_sec, 2, width, pad); + if ((flags & TM_SUBSECOND) && (format - 2) != oformat) + { + p = ".%N"; + goto push; + } + continue; + case 't': + if (cp < ep) + *cp++ = '\t'; + continue; + case 'T': + p = tm_info.format[TM_TIME]; + goto push; + case 'u': /* weekday number [1(Monday)-7] */ + if (!(i = tm->tm_wday)) + i = 7; + cp = number(cp, ep, (long)i, 0, width, pad); + continue; + case 'U': /* week number, Sunday as first day */ + cp = number(cp, ep, (long)tmweek(tm, 0, -1, -1), 2, width, pad); + continue; +#if 0 + case 'v': /* (UNUSED) */ + continue; +#endif + case 'V': /* ISO week number */ + cp = number(cp, ep, (long)tmweek(tm, 2, -1, -1), 2, width, pad); + continue; + case 'W': /* week number, Monday as first day */ + cp = number(cp, ep, (long)tmweek(tm, 1, -1, -1), 2, width, pad); + continue; + case 'w': /* weekday number [0(Sunday)-6] */ + cp = number(cp, ep, (long)tm->tm_wday, 0, width, pad); + continue; + case 'x': + p = tm_info.format[TM_DATE]; + goto push; + case 'X': + p = tm_info.format[TM_TIME]; + goto push; + case 'y': /* year in the form yy */ + cp = number(cp, ep, (long)(tm->tm_year % 100), 2, width, pad); + continue; + case 'Y': /* year in the form ccyy */ + cp = number(cp, ep, (long)(1900 + tm->tm_year), 4, width, pad); + continue; + case 'z': /* time zone west offset */ + if (arg) + { + if ((zp = tmzone(arg, &f, 0, 0)) && !*f && tm->tm_zone != zp) + tm = tmxtm(tm, tmxtime(tm, tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0)), zp); + continue; + } + if ((ep - cp) >= 16) + cp = tmpoff(cp, ep - cp, "", (flags & TM_UTC) ? 0 : tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0), pad == '_' ? -24 * 60 : 24 * 60); + continue; + case 'Z': /* time zone */ + if (arg) + { + if ((zp = tmzone(arg, &f, 0, 0)) && !*f && tm->tm_zone != zp) + tm = tmxtm(tm, tmxtime(tm, tm->tm_zone->west + (tm->tm_isdst ? tm->tm_zone->dst : 0)), zp); + continue; + } + p = (flags & TM_UTC) ? tm_info.format[TM_UT] : tm->tm_isdst && tm->tm_zone->daylight ? tm->tm_zone->daylight : tm->tm_zone->standard; + goto string; + case '=': /* (AST) OBSOLETE use %([+-]flag...)Qo (old %=[=][+-]flag) */ + for (arg = argbuf; *format == '=' || *format == '-' || *format == '+' || *format == '!'; format++) + if (arg < &argbuf[sizeof(argbuf) - 2]) + *arg++ = *format; + if (*arg++ = *format) + format++; + *arg = 0; + arg = argbuf; + goto options; + default: + if (cp < ep) + *cp++ = '%'; + if (cp < ep) + *cp++ = c; + continue; + } + index: + p = tm_info.format[n]; + string: + while (cp < ep && (*cp = *p++)) + cp++; + continue; + options: + c = '+'; + i = 0; + for (;;) + { + switch (*arg++) + { + case 0: + n = 0; + break; + case '=': + i = !i; + continue; + case '+': + case '-': + case '!': + c = *(arg - 1); + continue; + case 'l': + n = TM_LEAP; + break; + case 'n': + case 's': + n = TM_SUBSECOND; + break; + case 'u': + n = TM_UTC; + break; + default: + continue; + } + if (!n) + break; + + /* + * right, the global state stinks + * but we respect its locale-like status + */ + + if (c == '+') + { + if (!(flags & n)) + { + flags |= n; + tm_info.flags |= n; + tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone); + if (!i) + tm_info.flags &= ~n; + } + } + else if (flags & n) + { + flags &= ~n; + tm_info.flags &= ~n; + tm = tmxtm(tm, t, (flags & TM_UTC) ? &tm_data.zone[2] : tm->tm_zone); + if (!i) + tm_info.flags |= n; + } + } + continue; + push: + c = 0; + push_delimiter: + if (sp < &stack[elementsof(stack)]) + { + sp->format = (char*)format; + format = p; + sp->delimiter = delimiter; + delimiter = c; + sp++; + } + continue; + } + tm_info.flags = flags; + if (cp >= ep) + cp = ep - 1; + *cp = 0; + return cp; +} diff --git a/src/lib/libast/tm/tmxgettime.c b/src/lib/libast/tm/tmxgettime.c new file mode 100644 index 0000000..7ce13f3 --- /dev/null +++ b/src/lib/libast/tm/tmxgettime.c @@ -0,0 +1,44 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + */ + +#include <tmx.h> +#include <tv.h> + +/* + * return current Time_t + */ + +Time_t +tmxgettime(void) +{ + Tv_t tv; + + tvgettime(&tv); + return tmxsns(tv.tv_sec, tv.tv_nsec); +} diff --git a/src/lib/libast/tm/tmxleap.c b/src/lib/libast/tm/tmxleap.c new file mode 100644 index 0000000..ce07c5a --- /dev/null +++ b/src/lib/libast/tm/tmxleap.c @@ -0,0 +1,51 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + */ + +#include <tmx.h> + +/* + * return t with leap seconds adjusted + * for direct localtime() access + */ + +Time_t +tmxleap(Time_t t) +{ + register Tm_leap_t* lp; + uint32_t sec; + + tmset(tm_info.zone); + if (tm_info.flags & TM_ADJUST) + { + sec = tmxsec(t); + for (lp = &tm_data.leap[0]; sec < (lp->time - lp->total); lp++); + t = tmxsns(sec + lp->total, tmxnsec(t)); + } + return t; +} diff --git a/src/lib/libast/tm/tmxmake.c b/src/lib/libast/tm/tmxmake.c new file mode 100644 index 0000000..a985633 --- /dev/null +++ b/src/lib/libast/tm/tmxmake.c @@ -0,0 +1,140 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + */ + +#include <tmx.h> + +#include "FEATURE/tmlib" + +/* + * return Tm_t for t + * time zone and leap seconds accounted for in return value + */ + +Tm_t* +tmxtm(register Tm_t* tm, Time_t t, Tm_zone_t* zone) +{ + register struct tm* tp; + register Tm_leap_t* lp; + Time_t x; + time_t now; + int leapsec; + int y; + uint32_t n; + int32_t o; +#if TMX_FLOAT + Time_t z; + uint32_t i; +#endif + + tmset(tm_info.zone); + leapsec = 0; + if ((tm_info.flags & (TM_ADJUST|TM_LEAP)) == (TM_ADJUST|TM_LEAP) && (n = tmxsec(t))) + { + for (lp = &tm_data.leap[0]; n < lp->time; lp++); + if (lp->total) + { + if (n == lp->time && (leapsec = (lp->total - (lp+1)->total)) < 0) + leapsec = 0; + t = tmxsns(n - lp->total, tmxnsec(t)); + } + } + x = tmxsec(t); + if (!(tm->tm_zone = zone)) + { + if (tm_info.flags & TM_UTC) + tm->tm_zone = &tm_data.zone[2]; + else + tm->tm_zone = tm_info.zone; + } + if ((o = 60 * tm->tm_zone->west) && x > o) + { + x -= o; + o = 0; + } +#if TMX_FLOAT + i = x / (24 * 60 * 60); + z = i; + n = x - z * (24 * 60 * 60); + tm->tm_sec = n % 60 + leapsec; + n /= 60; + tm->tm_min = n % 60; + n /= 60; + tm->tm_hour = n % 24; +#define x i +#else + tm->tm_sec = x % 60 + leapsec; + x /= 60; + tm->tm_min = x % 60; + x /= 60; + tm->tm_hour = x % 24; + x /= 24; +#endif + tm->tm_wday = (x + 4) % 7; + tm->tm_year = (400 * (x + 25202)) / 146097 + 1; + n = tm->tm_year - 1; + x -= n * 365 + n / 4 - n / 100 + (n + (1900 - 1600)) / 400 - (1970 - 1901) * 365 - (1970 - 1901) / 4; + tm->tm_mon = 0; + tm->tm_mday = x + 1; + tm->tm_nsec = tmxnsec(t); + tmfix(tm); + n += 1900; + tm->tm_isdst = 0; + if (tm->tm_zone->daylight) + { + if ((y = tmequiv(tm) - 1900) == tm->tm_year) + now = tmxsec(t); + else + { + Tm_t te; + + te = *tm; + te.tm_year = y; + now = tmxsec(tmxtime(&te, tm->tm_zone->west)); + } + if ((tp = tmlocaltime(&now)) && ((tm->tm_isdst = tp->tm_isdst) || o)) + { + tm->tm_min -= o / 60 + (tm->tm_isdst ? tm->tm_zone->dst : 0); + tmfix(tm); + } + } + return tm; +} + +/* + * return Tm_t for t + * time zone and leap seconds accounted for in return value + */ + +Tm_t* +tmxmake(Time_t t) +{ + static Tm_t ts; + + return tmxtm(&ts, t, NiL); +} diff --git a/src/lib/libast/tm/tmxscan.c b/src/lib/libast/tm/tmxscan.c new file mode 100644 index 0000000..98d4749 --- /dev/null +++ b/src/lib/libast/tm/tmxscan.c @@ -0,0 +1,533 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + * + * scan date expression in s using format + * if non-null, e points to the first invalid sequence in s + * if non-null, f points to the first unused format char + * t provides default values + */ + +#include <tmx.h> +#include <ctype.h> + +typedef struct +{ + int32_t nsec; + int year; + int mon; + int week; + int weektype; + int yday; + int mday; + int wday; + int hour; + int min; + int sec; + int meridian; + int zone; +} Set_t; + +#define CLEAR(s) (s.year=s.mon=s.week=s.weektype=s.yday=s.mday=s.wday=s.hour=s.min=s.sec=s.meridian=(-1),s.nsec=1000000000L,s.zone=TM_LOCALZONE) + +#define INDEX(m,x) (((n)>=((x)-(m)))?((n)-=((x)-(m))):(n)) + +#define NUMBER(d,m,x) do \ + { \ + n = 0; \ + u = (char*)s; \ + while (s < (const char*)(u + d) && *s >= '0' && *s <= '9') \ + n = n * 10 + *s++ - '0'; \ + if (u == (char*)s || n < m || n > x) \ + goto next; \ + } while (0) + +/* + * generate a Time_t from tm + set + */ + +static Time_t +gen(register Tm_t* tm, register Set_t* set) +{ + register int n; + int z; + Time_t t; + + if (set->year >= 0) + tm->tm_year = set->year; + if (set->mon >= 0) + { + if (set->year < 0 && set->mon < tm->tm_mon) + tm->tm_year++; + tm->tm_mon = set->mon; + if (set->yday < 0 && set->mday < 0) + tm->tm_mday = set->mday = 1; + } + if (set->week >= 0) + { + if (set->mon < 0) + { + tmweek(tm, set->weektype, set->week, set->wday); + set->wday = -1; + } + } + else if (set->yday >= 0) + { + if (set->mon < 0) + { + tm->tm_mon = 0; + tm->tm_mday = set->yday + 1; + } + } + else if (set->mday >= 0) + tm->tm_mday = set->mday; + if (set->hour >= 0) + { + if (set->hour < tm->tm_hour && set->yday < 0 && set->mday < 0 && set->wday < 0) + tm->tm_mday++; + tm->tm_hour = set->hour; + tm->tm_min = (set->min >= 0) ? set->min : 0; + tm->tm_sec = (set->sec >= 0) ? set->sec : 0; + } + else if (set->min >= 0) + { + tm->tm_min = set->min; + tm->tm_sec = (set->sec >= 0) ? set->sec : 0; + } + else if (set->sec >= 0) + tm->tm_sec = set->sec; + if (set->nsec < 1000000000L) + tm->tm_nsec = set->nsec; + if (set->meridian > 0) + { + if (tm->tm_hour < 12) + tm->tm_hour += 12; + } + else if (set->meridian == 0) + { + if (tm->tm_hour >= 12) + tm->tm_hour -= 12; + } + t = tmxtime(tm, set->zone); + if (set->yday >= 0) + { + z = 1; + tm = tmxtm(tm, t, tm->tm_zone); + tm->tm_mday += set->yday - tm->tm_yday; + } + else if (set->wday >= 0) + { + z = 1; + tm = tmxtm(tm, t, tm->tm_zone); + if ((n = set->wday - tm->tm_wday) < 0) + n += 7; + tm->tm_mday += n; + } + else + z = 0; + if (set->nsec < 1000000000L) + { + if (!z) + { + z = 1; + tm = tmxtm(tm, t, tm->tm_zone); + } + tm->tm_nsec = set->nsec; + } + return z ? tmxtime(tm, set->zone) : t; +} + +/* + * the format scan workhorse + */ + +static Time_t +scan(register const char* s, char** e, const char* format, char** f, Time_t t, long flags) +{ + register int d; + register int n; + register char* p; + register Tm_t* tm; + const char* b; + char* u; + char* stack[4]; + int m; + int hi; + int lo; + int pedantic; + Time_t x; + Set_t set; + Tm_zone_t* zp; + Tm_t ts; + + char** sp = &stack[0]; + + while (isspace(*s)) + s++; + b = s; + again: + CLEAR(set); + tm = tmxtm(&ts, t, NiL); + pedantic = (flags & TM_PEDANTIC) != 0; + for (;;) + { + if (!(d = *format++)) + { + if (sp <= &stack[0]) + { + format--; + break; + } + format = (const char*)*--sp; + } + else if (!*s) + { + format--; + break; + } + else if (d == '%' && (d = *format) && format++ && d != '%') + { + more: + switch (d) + { + case 'a': + lo = TM_DAY_ABBREV; + hi = pedantic ? TM_DAY : TM_TIME; + goto get_wday; + case 'A': + lo = pedantic ? TM_DAY : TM_DAY_ABBREV; + hi = TM_TIME; + get_wday: + if ((n = tmlex(s, &u, tm_info.format + lo, hi - lo, NiL, 0)) < 0) + goto next; + s = u; + INDEX(TM_DAY_ABBREV, TM_DAY); + set.wday = n; + continue; + case 'b': + case 'h': + lo = TM_MONTH_ABBREV; + hi = pedantic ? TM_MONTH : TM_DAY_ABBREV; + goto get_mon; + case 'B': + lo = pedantic ? TM_MONTH : TM_MONTH_ABBREV; + hi = TM_DAY_ABBREV; + get_mon: + if ((n = tmlex(s, &u, tm_info.format + lo, hi - lo, NiL, 0)) < 0) + goto next; + s = u; + INDEX(TM_MONTH_ABBREV, TM_MONTH); + set.mon = n; + continue; + case 'c': + p = "%a %b %e %T %Y"; + break; + case 'C': + NUMBER(2, 19, 99); + set.year = (n - 19) * 100 + tm->tm_year % 100; + continue; + case 'd': + if (pedantic && !isdigit(*s)) + goto next; + /*FALLTHROUGH*/ + case 'e': + NUMBER(2, 1, 31); + set.mday = n; + continue; + case 'D': + p = "%m/%d/%y"; + break; + case 'E': + case 'O': + if (*format) + { + d = *format++; + goto more; + } + continue; + case 'F': + p = "%Y-%m-%d"; + break; + case 'H': + case 'k': + NUMBER(2, 0, 23); + set.hour = n; + continue; + case 'I': + case 'l': + NUMBER(2, 1, 12); + set.hour = n; + continue; + case 'j': + NUMBER(3, 1, 366); + set.yday = n - 1; + continue; + case 'm': + NUMBER(2, 1, 12); + set.mon = n - 1; + continue; + case 'M': + NUMBER(2, 0, 59); + set.min = n; + continue; + case 'n': + if (pedantic) + while (*s == '\n') + s++; + else + while (isspace(*s)) + s++; + continue; + case 'N': + NUMBER(9, 0, 999999999L); + set.nsec = n; + continue; + case 'p': + if ((n = tmlex(s, &u, tm_info.format + TM_MERIDIAN, TM_UT - TM_MERIDIAN, NiL, 0)) < 0) + goto next; + set.meridian = n; + s = u; + continue; + case 'r': + p = "%I:%M:%S %p"; + break; + case 'R': + p = "%H:%M:%S"; + break; + case 's': + x = strtoul(s, &u, 0); + if (s == u) + goto next; + tm = tmxtm(tm, tmxsns(x, 0), tm->tm_zone); + s = u; + CLEAR(set); + continue; + case 'S': + NUMBER(2, 0, 61); + set.sec = n; + continue; + case 'u': + NUMBER(2, 1, 7); + set.wday = n % 7; + continue; + case 'U': + NUMBER(2, 0, 52); + set.week = n; + set.weektype = 0; + continue; + case 'V': + NUMBER(2, 1, 53); + set.week = n; + set.weektype = 2; + continue; + case 'w': + NUMBER(2, 0, 6); + set.wday = n; + continue; + case 'W': + NUMBER(2, 0, 52); + set.week = n; + set.weektype = 1; + continue; + case 'x': + p = tm_info.format[TM_DATE]; + break; + case 'X': + p = tm_info.format[TM_TIME]; + break; + case 'y': + NUMBER(2, 0, 99); + if (n < TM_WINDOW) + n += 100; + set.year = n; + continue; + case 'Y': + NUMBER(4, 1969, 2100); + set.year = n - 1900; + continue; + case 'Z': + case 'q': + if (zp = tmtype(s, &u)) + { + s = u; + u = zp->type; + } + else + u = 0; + if (d == 'q') + continue; + case 'z': + if ((zp = tmzone(s, &u, u, &m))) + { + s = u; + set.zone = zp->west + m; + tm_info.date = zp; + } + continue; + case '|': + s = b; + goto again; + case '&': + x = gen(tm, &set); + x = tmxdate(s, e, t); + if (s == (const char*)*e) + goto next; + t = x; + s = (const char*)*e; + if (!*format || *format == '%' && *(format + 1) == '|') + goto done; + goto again; + default: + goto next; + } + if (sp >= &stack[elementsof(stack)]) + goto next; + *sp++ = (char*)format; + format = (const char*)p; + } + else if (isspace(d)) + while (isspace(*s)) + s++; + else if (*s != d) + break; + else + s++; + } + next: + if (sp > &stack[0]) + format = (const char*)stack[0]; + if (*format) + { + p = (char*)format; + if (!*s && *p == '%' && *(p + 1) == '|') + format += strlen(format); + else + while (*p) + if (*p++ == '%' && *p && *p++ == '|' && *p) + { + format = (const char*)p; + s = b; + goto again; + } + } + t = gen(tm, &set); + done: + if (e) + { + while (isspace(*s)) + s++; + *e = (char*)s; + } + if (f) + { + while (isspace(*format)) + format++; + *f = (char*)format; + } + return t; +} + +/* + * format==0 DATEMSK + * *format==0 DATEMSK and tmxdate() + * *format!=0 format + */ + +Time_t +tmxscan(const char* s, char** e, const char* format, char** f, Time_t t, long flags) +{ + register char* v; + register char** p; + char* q; + char* r; + Time_t x; + + static int initialized; + static char** datemask; + + tmlocale(); + if (!format || !*format) + { + if (!initialized) + { + register Sfio_t* sp; + register int n; + off_t m; + + initialized = 1; + if ((v = getenv("DATEMSK")) && *v && (sp = sfopen(NiL, v, "r"))) + { + for (n = 1; sfgetr(sp, '\n', 0); n++); + m = sfseek(sp, 0L, SEEK_CUR); + if (p = newof(0, char*, n, m)) + { + sfseek(sp, 0L, SEEK_SET); + v = (char*)(p + n); + if (sfread(sp, v, m) != m) + { + free(p); + p = 0; + } + else + { + datemask = p; + v[m] = 0; + while (*v) + { + *p++ = v; + if (!(v = strchr(v, '\n'))) + break; + *v++ = 0; + } + *p = 0; + } + } + } + } + if (p = datemask) + while (v = *p++) + { + x = scan(s, &q, v, &r, t, flags); + if (!*q && !*r) + { + if (e) + *e = q; + if (f) + *f = r; + return x; + } + } + if (f) + *f = (char*)format; + if (format) + return tmxdate(s, e, t); + if (e) + *e = (char*)s; + return 0; + } + return scan(s, e, format, f, t, flags); +} diff --git a/src/lib/libast/tm/tmxsettime.c b/src/lib/libast/tm/tmxsettime.c new file mode 100644 index 0000000..90bee75 --- /dev/null +++ b/src/lib/libast/tm/tmxsettime.c @@ -0,0 +1,45 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + */ + +#include <tmx.h> +#include <tv.h> + +/* + * return current current time to t + */ + +int +tmxsettime(Time_t t) +{ + Tv_t tv; + + tv.tv_sec = tmxsec(t); + tv.tv_nsec = tmxnsec(t); + return tvsettime(&tv); +} diff --git a/src/lib/libast/tm/tmxsleep.c b/src/lib/libast/tm/tmxsleep.c new file mode 100644 index 0000000..9de8f9a --- /dev/null +++ b/src/lib/libast/tm/tmxsleep.c @@ -0,0 +1,41 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t sleep + */ + +#include <tmx.h> +#include <tv.h> + +int +tmxsleep(Time_t t) +{ + Tv_t tv; + + tv.tv_sec = tmxsec(t); + tv.tv_nsec = tmxnsec(t); + return tvsleep(&tv, NiL); +} diff --git a/src/lib/libast/tm/tmxtime.c b/src/lib/libast/tm/tmxtime.c new file mode 100644 index 0000000..6951f8a --- /dev/null +++ b/src/lib/libast/tm/tmxtime.c @@ -0,0 +1,137 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + */ + +#include <tmx.h> + +#include "FEATURE/tmlib" + +/* + * convert Tm_t to Time_t + * + * if west==TM_LOCALZONE then the local timezone is used + * otherwise west is the number of minutes west + * of GMT with DST taken into account + * + * this routine works with a copy of Tm_t to avoid clashes + * with other tm*() that may return static Tm_t* + */ + +Time_t +tmxtime(register Tm_t* tm, int west) +{ + register Time_t t; + register Tm_leap_t* lp; + register int32_t y; + int n; + int sec; + time_t now; + struct tm* tl; + Tm_t* to; + Tm_t ts; + + ts = *tm; + to = tm; + tm = &ts; + tmset(tm_info.zone); + tmfix(tm); + y = tm->tm_year; + if (y < 69 || y > (TMX_MAXYEAR - 1900)) + return TMX_NOTIME; + y--; + t = y * 365 + y / 4 - y / 100 + (y + (1900 - 1600)) / 400 - (1970 - 1901) * 365 - (1970 - 1901) / 4; + if ((n = tm->tm_mon) > 11) + n = 11; + y += 1901; + if (n > 1 && tmisleapyear(y)) + t++; + t += tm_data.sum[n] + tm->tm_mday - 1; + t *= 24; + t += tm->tm_hour; + t *= 60; + t += tm->tm_min; + t *= 60; + t += sec = tm->tm_sec; + if (west != TM_UTCZONE && !(tm_info.flags & TM_UTC)) + { + /* + * time zone adjustments + */ + + if (west == TM_LOCALZONE) + { + t += tm_info.zone->west * 60; + if (!tm_info.zone->daylight) + tm->tm_isdst = 0; + else + { + y = tm->tm_year; + tm->tm_year = tmequiv(tm) - 1900; + now = tmxsec(tmxtime(tm, tm_info.zone->west)); + tm->tm_year = y; + if (!(tl = tmlocaltime(&now))) + return TMX_NOTIME; + if (tm->tm_isdst = tl->tm_isdst) + t += tm_info.zone->dst * 60; + } + } + else + { + t += west * 60; + if (!tm_info.zone->daylight) + tm->tm_isdst = 0; + else if (tm->tm_isdst < 0) + { + y = tm->tm_year; + tm->tm_year = tmequiv(tm) - 1900; + tm->tm_isdst = 0; + now = tmxsec(tmxtime(tm, tm_info.zone->west)); + tm->tm_year = y; + if (!(tl = tmlocaltime(&now))) + return TMX_NOTIME; + tm->tm_isdst = tl->tm_isdst; + } + } + } + else if (tm->tm_isdst) + tm->tm_isdst = 0; + *to = *tm; + if (tm_info.flags & TM_LEAP) + { + /* + * leap second adjustments + */ + + for (lp = &tm_data.leap[0]; t < lp->time - (lp+1)->total; lp++); + t += lp->total; + n = lp->total - (lp+1)->total; + if (t <= (lp->time + n) && (n > 0 && sec > 59 || n < 0 && sec > (59 + n) && sec <= 59)) + t -= n; + } + return tmxsns(t, tm->tm_nsec); +} diff --git a/src/lib/libast/tm/tmxtouch.c b/src/lib/libast/tm/tmxtouch.c new file mode 100644 index 0000000..e711a62 --- /dev/null +++ b/src/lib/libast/tm/tmxtouch.c @@ -0,0 +1,81 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Time_t conversion support + */ + +#include <tmx.h> +#include <tv.h> + +/* + * touch path <atime,mtime,ctime> + * (flags&PATH_TOUCH_VERBATIM) treats times verbatim, otherwise: + * Time_t==0 current time + * Time_t==TMX_NOTIME retains path value + */ + +int +tmxtouch(const char* path, Time_t at, Time_t mt, Time_t ct, int flags) +{ + Tv_t av; + Tv_t mv; + Tv_t cv; + Tv_t* ap; + Tv_t* mp; + Tv_t* cp; + + if (at == TMX_NOTIME && !(flags & PATH_TOUCH_VERBATIM)) + ap = TV_TOUCH_RETAIN; + else if (!at && !(flags & PATH_TOUCH_VERBATIM)) + ap = 0; + else + { + av.tv_sec = tmxsec(at); + av.tv_nsec = tmxnsec(at); + ap = &av; + } + if (mt == TMX_NOTIME && !(flags & PATH_TOUCH_VERBATIM)) + mp = TV_TOUCH_RETAIN; + else if (!mt && !(flags & PATH_TOUCH_VERBATIM)) + mp = 0; + else + { + mv.tv_sec = tmxsec(mt); + mv.tv_nsec = tmxnsec(mt); + mp = &mv; + } + if (ct == TMX_NOTIME && !(flags & PATH_TOUCH_VERBATIM)) + cp = TV_TOUCH_RETAIN; + else if (!ct && !(flags & PATH_TOUCH_VERBATIM)) + cp = 0; + else + { + cv.tv_sec = tmxsec(ct); + cv.tv_nsec = tmxnsec(ct); + cp = &cv; + } + return tvtouch(path, ap, mp, cp, flags & 1); +} diff --git a/src/lib/libast/tm/tmzone.c b/src/lib/libast/tm/tmzone.c new file mode 100644 index 0000000..230a5f3 --- /dev/null +++ b/src/lib/libast/tm/tmzone.c @@ -0,0 +1,95 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * time conversion support + */ + +#include <ast.h> +#include <tm.h> + +/* + * return timezone pointer given name and type + * + * if type==0 then all time zone types match + * otherwise type must be one of tm_info.zone[].type + * + * if end is non-null then it will point to the next + * unmatched char in name + * + * if dst!=0 then it will point to 0 for standard zones + * and the offset for daylight zones + * + * 0 returned for no match + */ + +Tm_zone_t* +tmzone(register const char* name, char** end, const char* type, int* dst) +{ + register Tm_zone_t* zp; + register char* prev; + char* e; + + static Tm_zone_t fixed; + static char off[16]; + + tmset(tm_info.zone); + if ((*name == '+' || *name == '-') && (fixed.west = tmgoff(name, &e, TM_LOCALZONE)) != TM_LOCALZONE && !*e) + { + strlcpy(fixed.standard = fixed.daylight = off, name, sizeof(off)); + if (end) + *end = e; + if (dst) + *dst = 0; + return &fixed; + } + zp = tm_info.local; + prev = 0; + do + { + if (zp->type) + prev = zp->type; + if (!type || type == prev || !prev) + { + if (tmword(name, end, zp->standard, NiL, 0)) + { + if (dst) + *dst = 0; + return zp; + } + if (zp->dst && zp->daylight && tmword(name, end, zp->daylight, NiL, 0)) + { + if (dst) + *dst = zp->dst; + return zp; + } + } + if (zp == tm_info.local) + zp = tm_data.zone; + else + zp++; + } while (zp->standard); + return 0; +} diff --git a/src/lib/libast/tm/tvcmp.c b/src/lib/libast/tm/tvcmp.c new file mode 100644 index 0000000..2716d3d --- /dev/null +++ b/src/lib/libast/tm/tvcmp.c @@ -0,0 +1,46 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped + +#include <tv.h> + +/* + * compare a with b + * strcmp semantics + */ + +int +tvcmp(register const Tv_t* a, register const Tv_t* b) +{ + if (a->tv_sec < b->tv_sec) + return -1; + if (a->tv_sec > b->tv_sec) + return 1; + if (a->tv_nsec != TV_NSEC_IGNORE && b->tv_nsec != TV_NSEC_IGNORE) + { + if (a->tv_nsec < b->tv_nsec) + return -1; + if (a->tv_nsec > b->tv_nsec) + return 1; + } + return 0; +} diff --git a/src/lib/libast/tm/tvgettime.c b/src/lib/libast/tm/tvgettime.c new file mode 100644 index 0000000..12866e3 --- /dev/null +++ b/src/lib/libast/tm/tvgettime.c @@ -0,0 +1,70 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped + +#include <tv.h> +#include <tm.h> + +#include "FEATURE/tvlib" + +int +tvgettime(Tv_t* tv) +{ + +#if _lib_clock_gettime && defined(CLOCK_REALTIME) + + struct timespec s; + + clock_gettime(CLOCK_REALTIME, &s); + tv->tv_sec = s.tv_sec; + tv->tv_nsec = s.tv_nsec; + +#else + +#if defined(tmgettimeofday) + + struct timeval v; + + tmgettimeofday(&v); + tv->tv_sec = v.tv_sec; + tv->tv_nsec = v.tv_usec * 1000; + +#else + + static time_t s; + static uint32_t n; + + if ((tv->tv_sec = time(NiL)) != s) + { + s = tv->tv_sec; + n = 0; + } + else + n += 1000; + tv->tv_nsec = n; + +#endif + +#endif + + return 0; +} diff --git a/src/lib/libast/tm/tvsettime.c b/src/lib/libast/tm/tvsettime.c new file mode 100644 index 0000000..4e3842b --- /dev/null +++ b/src/lib/libast/tm/tvsettime.c @@ -0,0 +1,72 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped + +#include <tv.h> +#include <tm.h> +#include <errno.h> + +#include "FEATURE/tvlib" + +int +tvsettime(const Tv_t* tv) +{ + +#if _lib_clock_settime && defined(CLOCK_REALTIME) + + struct timespec s; + + s.tv_sec = tv->tv_sec; + s.tv_nsec = tv->tv_nsec; + return clock_settime(CLOCK_REALTIME, &s); + +#else + +#if defined(tmsettimeofday) + + struct timeval v; + + v.tv_sec = tv->tv_sec; + v.tv_usec = tv->tv_nsec / 1000; + return tmsettimeofday(&v); + +#else + +#if _lib_stime + + static time_t s; + + s = tv->tv_sec + (tv->tv_nsec != 0); + return stime(s); + +#else + + errno = EPERM; + return -1; + +#endif + +#endif + +#endif + +} diff --git a/src/lib/libast/tm/tvsleep.c b/src/lib/libast/tm/tvsleep.c new file mode 100644 index 0000000..78da802 --- /dev/null +++ b/src/lib/libast/tm/tvsleep.c @@ -0,0 +1,144 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped + +#include <tv.h> +#include <tm.h> + +#include "FEATURE/tvlib" + +#if !_lib_nanosleep +# if _lib_select +# if _sys_select +# include <sys/select.h> +# else +# include <sys/socket.h> +# endif +# else +# if !_lib_usleep +# if _lib_poll_notimer +# undef _lib_poll +# endif +# if _lib_poll +# include <poll.h> +# endif +# endif +# endif +#endif + +/* + * sleep for tv + * non-zero exit if sleep did not complete + * with remaining time in rv + */ + +int +tvsleep(register const Tv_t* tv, register Tv_t* rv) +{ + +#if _lib_nanosleep + + struct timespec stv; + struct timespec srv; + int r; + + stv.tv_sec = tv->tv_sec; + stv.tv_nsec = tv->tv_nsec; + if ((r = nanosleep(&stv, &srv)) && rv) + { + rv->tv_sec = srv.tv_sec; + rv->tv_nsec = srv.tv_nsec; + } + return r; + +#else + +#if _lib_select + + struct timeval stv; + + stv.tv_sec = tv->tv_sec; + stv.tv_usec = tv->tv_nsec / 1000; + if (select(0, NiL, NiL, NiL, &stv) < 0) + { + if (rv) + *rv = *tv; + return -1; + } + if (rv) + { + rv->tv_sec = stv.tv_sec; + rv->tv_nsec = stv.tv_usec * 1000; + } + return 0; + +#else + + unsigned int s = tv->tv_sec; + uint32_t n = tv->tv_nsec; + +#if _lib_usleep + + + unsigned long t; + + if (t = (n + 999L) / 1000L) + { + usleep(t); + s -= t / 1000000L; + n = 0; + } + +#else + +#if _lib_poll + + struct pollfd pfd; + int t; + + if ((t = (n + 999999L) / 1000000L) > 0) + { + poll(&pfd, 0, t); + s -= t / 1000L; + n = 0; + } + +#endif + +#endif + + if ((s += (n + 999999999L) / 1000000000L) && (s = sleep(s))) + { + if (rv) + { + rv->tv_sec = s; + rv->tv_nsec = 0; + } + return -1; + } + return 0; + +#endif + +#endif + +} diff --git a/src/lib/libast/tm/tvtouch.c b/src/lib/libast/tm/tvtouch.c new file mode 100644 index 0000000..bd5fb5c --- /dev/null +++ b/src/lib/libast/tm/tvtouch.c @@ -0,0 +1,295 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * Glenn Fowler + * AT&T Research + * + * Tv_t conversion support + */ + +#if defined(__STDPP__directive) && defined(__STDPP__hide) +__STDPP__directive pragma pp:hide utime +#else +#define utime ______utime +#endif + +#ifndef _ATFILE_SOURCE +#define _ATFILE_SOURCE 1 +#endif + +#include <ast.h> +#include <ls.h> +#include <tv.h> +#include <times.h> +#include <error.h> + +#include "FEATURE/tvlib" + +#if _hdr_utime && _lib_utime +#include <utime.h> +#endif + +#if defined(__STDPP__directive) && defined(__STDPP__hide) +__STDPP__directive pragma pp:nohide utime +#else +#undef utime +#endif + +#if _lib_utime +#if _hdr_utime +extern int utime(const char*, const struct utimbuf*); +#else +extern int utime(const char*, const time_t*); +#endif +#endif + +#define NS(n) (((uint32_t)(n))<1000000000L?(n):0) + +/* + * touch path <atime,mtime,ctime> + * Tv_t==0 uses current time + * Tv_t==TV_TOUCH_RETAIN retains path value if it exists, current time otherwise + * otherwise it is exact time + * file created if it doesn't exist and (flags&TV_TOUCH_CREATE) + * symlink not followed if (flags&TV_TOUCH_PHYSICAL) + * cv most likely ignored on most implementations + * + * NOTE: when *at() calls are integrated TV_TOUCH_* should be advertized! + */ + +#define TV_TOUCH_CREATE 1 +#define TV_TOUCH_PHYSICAL 2 + +#if !defined(UTIME_NOW) || !defined(UTIME_OMIT) || defined(__stub_utimensat) +#undef _lib_utimensat +#endif + +int +tvtouch(const char* path, register const Tv_t* av, register const Tv_t* mv, const Tv_t* cv, int flags) +{ + int fd; + int mode; + int oerrno; + struct stat st; + Tv_t now; +#if _lib_utimets || _lib_utimensat + struct timespec ts[2]; +#endif +#if _lib_utimes + struct timeval am[2]; +#else +#if _hdr_utime + struct utimbuf am; +#else + time_t am[2]; +#endif +#endif + + oerrno = errno; +#if _lib_utimensat + if (!av) + { + ts[0].tv_sec = 0; + ts[0].tv_nsec = UTIME_NOW; + } + else if (av == TV_TOUCH_RETAIN) + { + ts[0].tv_sec = 0; + ts[0].tv_nsec = UTIME_OMIT; + } + else + { + ts[0].tv_sec = av->tv_sec; + ts[0].tv_nsec = NS(av->tv_nsec); + } + if (!mv) + { + ts[1].tv_sec = 0; + ts[1].tv_nsec = UTIME_NOW; + } + else if (mv == TV_TOUCH_RETAIN) + { + ts[1].tv_sec = 0; + ts[1].tv_nsec = UTIME_OMIT; + } + else + { + ts[1].tv_sec = mv->tv_sec; + ts[1].tv_nsec = NS(mv->tv_nsec); + } + if (!cv && av == TV_TOUCH_RETAIN && mv == TV_TOUCH_RETAIN && !stat(path, &st) && !chmod(path, st.st_mode & S_IPERM)) + return 0; + if (!utimensat(AT_FDCWD, path, ts[0].tv_nsec == UTIME_NOW && ts[1].tv_nsec == UTIME_NOW ? (struct timespec*)0 : ts, (flags & TV_TOUCH_PHYSICAL) ? AT_SYMLINK_NOFOLLOW : 0)) + return 0; + if (errno != ENOSYS) + { + if (errno != ENOENT || !(flags & TV_TOUCH_CREATE)) + return -1; + umask(mode = umask(0)); + mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) + return -1; + close(fd); + errno = oerrno; + if ((ts[0].tv_nsec != UTIME_NOW || ts[1].tv_nsec != UTIME_NOW) && utimensat(AT_FDCWD, path, ts, (flags & TV_TOUCH_PHYSICAL) ? AT_SYMLINK_NOFOLLOW : 0)) + return -1; + return 0; + } +#endif + if ((av == TV_TOUCH_RETAIN || mv == TV_TOUCH_RETAIN) && stat(path, &st)) + { + errno = oerrno; + if (av == TV_TOUCH_RETAIN) + av = 0; + if (mv == TV_TOUCH_RETAIN) + mv = 0; + } + if (!av || !mv) + { + tvgettime(&now); + if (!av) + av = (const Tv_t*)&now; + if (!mv) + mv = (const Tv_t*)&now; + } +#if _lib_utimets + if (av == TV_TOUCH_RETAIN) + { + ts[0].tv_sec = st.st_atime; + ts[0].tv_nsec = ST_ATIME_NSEC_GET(&st); + } + else + { + ts[0].tv_sec = av->tv_sec; + ts[0].tv_nsec = NS(av->tv_nsec); + } + if (mv == TV_TOUCH_RETAIN) + { + ts[1].tv_sec = st.st_mtime; + ts[1].tv_nsec = ST_MTIME_NSEC_GET(&st); + } + else + { + ts[1].tv_sec = mv->tv_sec; + ts[1].tv_nsec = NS(mv->tv_nsec); + } + if (!utimets(path, ts)) + return 0; + if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimets(path, NiL)) + { + errno = oerrno; + return 0; + } +#else +#if _lib_utimes + if (av == TV_TOUCH_RETAIN) + { + am[0].tv_sec = st.st_atime; + am[0].tv_usec = ST_ATIME_NSEC_GET(&st) / 1000; + } + else + { + am[0].tv_sec = av->tv_sec; + am[0].tv_usec = NS(av->tv_nsec) / 1000; + } + if (mv == TV_TOUCH_RETAIN) + { + am[1].tv_sec = st.st_mtime; + am[1].tv_usec = ST_MTIME_NSEC_GET(&st) / 1000; + } + else + { + am[1].tv_sec = mv->tv_sec; + am[1].tv_usec = NS(mv->tv_nsec) / 1000; + } + if (!utimes(path, am)) + return 0; + if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utimes(path, NiL)) + { + errno = oerrno; + return 0; + } +#else +#if _lib_utime + am.actime = (av == TV_TOUCH_RETAIN) ? st.st_atime : av->tv_sec; + am.modtime = (mv == TV_TOUCH_RETAIN) ? st.st_mtime : mv->tv_sec; + if (!utime(path, &am)) + return 0; +#if _lib_utime_now + if (errno != ENOENT && av == (const Tv_t*)&now && mv == (const Tv_t*)&now && !utime(path, NiL)) + { + errno = oerrno; + return 0; + } +#endif +#endif +#endif + if (!access(path, F_OK)) + { + if (av != (const Tv_t*)&now || mv != (const Tv_t*)&now) + { + errno = EINVAL; + return -1; + } + if ((fd = open(path, O_RDWR)) >= 0) + { + char c; + + if (read(fd, &c, 1) == 1) + { + if (c = (lseek(fd, 0L, 0) == 0L && write(fd, &c, 1) == 1)) + errno = oerrno; + close(fd); + if (c) + return 0; + } + close(fd); + } + } +#endif + if (errno != ENOENT || !(flags & TV_TOUCH_CREATE)) + return -1; + umask(mode = umask(0)); + mode = (~mode) & (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) + return -1; + close(fd); + errno = oerrno; + if (av == (const Tv_t*)&now && mv == (const Tv_t*)&now) + return 0; +#if _lib_utimets + return utimets(path, am); +#else +#if _lib_utimes + return utimes(path, am); +#else +#if _lib_utime + return utime(path, &am); +#else + errno = EINVAL; + return -1; +#endif +#endif +#endif + +} |