summaryrefslogtreecommitdiff
path: root/src/lib/libast/tm
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libast/tm')
-rw-r--r--src/lib/libast/tm/tmdata.c288
-rw-r--r--src/lib/libast/tm/tmdate.c41
-rw-r--r--src/lib/libast/tm/tmequiv.c57
-rw-r--r--src/lib/libast/tm/tmfix.c173
-rw-r--r--src/lib/libast/tm/tmfmt.c41
-rw-r--r--src/lib/libast/tm/tmform.c44
-rw-r--r--src/lib/libast/tm/tmgoff.c77
-rw-r--r--src/lib/libast/tm/tminit.c460
-rw-r--r--src/lib/libast/tm/tmleap.c41
-rw-r--r--src/lib/libast/tm/tmlex.c67
-rw-r--r--src/lib/libast/tm/tmlocale.c644
-rw-r--r--src/lib/libast/tm/tmmake.c41
-rw-r--r--src/lib/libast/tm/tmpoff.c62
-rw-r--r--src/lib/libast/tm/tmscan.c41
-rw-r--r--src/lib/libast/tm/tmsleep.c42
-rw-r--r--src/lib/libast/tm/tmtime.c41
-rw-r--r--src/lib/libast/tm/tmtype.c57
-rw-r--r--src/lib/libast/tm/tmweek.c87
-rw-r--r--src/lib/libast/tm/tmword.c89
-rw-r--r--src/lib/libast/tm/tmxdate.c1745
-rw-r--r--src/lib/libast/tm/tmxduration.c80
-rw-r--r--src/lib/libast/tm/tmxfmt.c703
-rw-r--r--src/lib/libast/tm/tmxgettime.c44
-rw-r--r--src/lib/libast/tm/tmxleap.c51
-rw-r--r--src/lib/libast/tm/tmxmake.c140
-rw-r--r--src/lib/libast/tm/tmxscan.c533
-rw-r--r--src/lib/libast/tm/tmxsettime.c45
-rw-r--r--src/lib/libast/tm/tmxsleep.c41
-rw-r--r--src/lib/libast/tm/tmxtime.c137
-rw-r--r--src/lib/libast/tm/tmxtouch.c81
-rw-r--r--src/lib/libast/tm/tmzone.c95
-rw-r--r--src/lib/libast/tm/tvcmp.c46
-rw-r--r--src/lib/libast/tm/tvgettime.c70
-rw-r--r--src/lib/libast/tm/tvsettime.c72
-rw-r--r--src/lib/libast/tm/tvsleep.c144
-rw-r--r--src/lib/libast/tm/tvtouch.c295
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
+
+}