packages feed

unix-time 0.3.8 → 0.4.0

raw patch · 9 files changed

+1594/−11 lines, 9 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Data.UnixTime: microSecondsToUnixDiffTime :: (Integral a) => a -> UnixDiffTime
+ Data.UnixTime: microSecondsToUnixDiffTime :: Integral a => a -> UnixDiffTime
- Data.UnixTime: secondsToUnixDiffTime :: (Integral a) => a -> UnixDiffTime
+ Data.UnixTime: secondsToUnixDiffTime :: Integral a => a -> UnixDiffTime

Files

Data/UnixTime/Types.hsc view
@@ -4,6 +4,9 @@ import Data.ByteString import Data.ByteString.Char8 () import Data.Int+#if defined(_WIN32)+import Data.Word+#endif import Foreign.C.Types import Foreign.Storable #if __GLASGOW_HASKELL__ >= 704@@ -34,12 +37,37 @@ instance Storable UnixTime where     sizeOf _    = (#size struct timeval)     alignment _ = (#const offsetof(struct {char x__; struct timeval (y__); }, y__))+#if defined(_WIN32)+    -- On windows, with mingw-w64, the struct `timeval` is defined as+    --+    --      struct timeval+    --      {+    --          long tv_sec;+    --          long tv_usec;+    --      };+    --+    -- The type `long` is 32bit on windows 64bit, however the CTime is 64bit, thus+    -- we must be careful about the layout of its foreign memory.+    --+    -- Here we try use Word32, rather than Int32, to support as large value as possible.+    -- For example, we use `4294967295` as utSeconds in testsuite, which already exceeds+    -- the range of Int32, but not for Word32.+    peek ptr    = do+            sec <- (#peek struct timeval, tv_sec) ptr :: IO Word32+            msec <- (#peek struct timeval, tv_usec) ptr+            return $ UnixTime (fromIntegral sec) msec+    poke ptr ut = do+            let CTime sec = utSeconds ut+            (#poke struct timeval, tv_sec)  ptr (fromIntegral sec :: Word32)+            (#poke struct timeval, tv_usec) ptr (utMicroSeconds ut)+#else     peek ptr    = UnixTime             <$> (#peek struct timeval, tv_sec)  ptr             <*> (#peek struct timeval, tv_usec) ptr     poke ptr ut = do             (#poke struct timeval, tv_sec)  ptr (utSeconds ut)             (#poke struct timeval, tv_usec) ptr (utMicroSeconds ut)+#endif  #if __GLASGOW_HASKELL__ >= 704 instance Binary UnixTime where
cbits/config.h.in view
@@ -30,6 +30,18 @@ /* Define to 1 if you have the `timegm' function. */ #undef HAVE_TIMEGM +/* Define to 1 if you have the `_mkgmtime' function. */+#undef HAVE__MKGMTIME++/* Define to 1 if you have the `_get_current_locale' function. */+#undef HAVE__GET_CURRENT_LOCALE++/* Define to 1 if you have the `strtol_l' function. */+#undef HAVE_STRTOL_L++/* Define to 1 if you have the `strtoll_l' function. */+#undef HAVE_STRTOLL_L+ /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H 
cbits/conv.c view
@@ -16,7 +16,12 @@ #include <time.h> #include <locale.h> #include <stdlib.h>+#include <stdio.h> +#if defined(_WIN32)+#include "win_patch.h"+#endif // _WIN32+ #if THREAD_SAFE #if HAVE_XLOCALE_H #include <xlocale.h>@@ -32,7 +37,7 @@     static int initialized = 0;     if (initialized == 0) {         setlocale(LC_TIME, "C");-	initialized == 1;+        initialized = 1;     } } #endif@@ -44,7 +49,11 @@ char *set_tz_utc() {     char *tz;     tz = getenv("TZ");+#if defined(_WIN32)+    _patch_setenv("TZ", "", 1);+#else     setenv("TZ", "", 1);+#endif     tzset();     return tz; }@@ -55,9 +64,17 @@  */ void set_tz(char *local_tz) {     if (local_tz) {+#if defined(_WIN32)+      _patch_setenv("TZ", local_tz, 1);+#else       setenv("TZ", local_tz, 1);+#endif     } else {+#if defined(_WIN32)+      _patch_unsetenv("TZ");+#else       unsetenv("TZ");+#endif     }     tzset(); }@@ -83,13 +100,6 @@  * All rights reserved.  */ -static int-is_leap(unsigned y)-{-  y += 1900;-  return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);-}- static time_t timegm (struct tm *tm) {@@ -100,10 +110,10 @@   unsigned i;    for (i = 70; i < tm->tm_year; ++i)-    res += is_leap(i) ? 366 : 365;+    res += isleap(i + 1900) ? 366 : 365;    for (i = 0; i < tm->tm_mon; ++i)-    res += ndays[is_leap(tm->tm_year)][i];+    res += ndays[isleap(tm->tm_year + 1900)][i];   res += tm->tm_mday - 1;   res *= 24;   res += tm->tm_hour;@@ -135,9 +145,17 @@     init_locale();     localtime_r(&src, &tim); #if THREAD_SAFE+#if defined(_WIN32)+    return _patch_strftime_l(dst, siz, fmt, &tim, c_locale);+#else     return strftime_l(dst, siz, fmt, &tim, c_locale);+#endif // _WIN32 #else+#if defined(_WIN32)+    return _patch_strftime(dst, siz, fmt, &tim);+#else     return strftime(dst, siz, fmt, &tim);+#endif // _WIN32 #endif } @@ -151,9 +169,17 @@      local_tz = set_tz_utc(); #if THREAD_SAFE+#if defined(_WIN32)+    dst_size = _patch_strftime_l(dst, siz, fmt, &tim, c_locale);+#else     dst_size = strftime_l(dst, siz, fmt, &tim, c_locale);+#endif // _WIN32 #else+#if defined(_WIN32)+    dst_size = _patch_strftime(dst, siz, fmt, &tim);+#else     dst_size = strftime(dst, siz, fmt, &tim);+#endif // _WIN32 #endif     set_tz(local_tz);     return dst_size;
+ cbits/strftime.c view
@@ -0,0 +1,628 @@+/*+ * Copyright (c) 1989 The Regents of the University of California.+ * All rights reserved.+ *+ * Copyright (c) 2011 The FreeBSD Foundation+ * All rights reserved.+ * Portions of this software were developed by David Chisnall+ * under sponsorship from the FreeBSD Foundation.+ *+ * Redistribution and use in source and binary forms are permitted+ * provided that the above copyright notice and this paragraph are+ * duplicated in all such forms and that any documentation,+ * advertising materials, and other materials related to such+ * distribution and use acknowledge that the software was developed+ * by the University of California, Berkeley. The name of the+ * University may not be used to endorse or promote products derived+ * from this software without specific prior written permission.+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.+ */++#include <fcntl.h>+#include <sys/cdefs.h>+#include <sys/stat.h>++#include <time.h>+#include <ctype.h>+#include <errno.h>+#include <locale.h>+#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <pthread.h>++#include "win_patch.h"++static char *	_add(const char *, char *, const char *);+static char *	_conv(int, const char *, char *, const char *, _locale_t);+static char *	_fmt(const char *, const struct tm *, char *, const char *,+			int *, _locale_t);+static char *	_yconv(int, int, int, int, char *, const char *, _locale_t);++#ifndef YEAR_2000_NAME+#define YEAR_2000_NAME	"CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"+#endif /* !defined YEAR_2000_NAME */++#define	IN_NONE	0+#define	IN_SOME	1+#define	IN_THIS	2+#define	IN_ALL	3++#define	PAD_DEFAULT	0+#define	PAD_LESS	1+#define	PAD_SPACE	2+#define	PAD_ZERO	3++static const char fmt_padding[][4][5] = {+	/* DEFAULT,	LESS,	SPACE,	ZERO */+#define	PAD_FMT_MONTHDAY	0+#define	PAD_FMT_HMS		0+#define	PAD_FMT_CENTURY		0+#define	PAD_FMT_SHORTYEAR	0+#define	PAD_FMT_MONTH		0+#define	PAD_FMT_WEEKOFYEAR	0+#define	PAD_FMT_DAYOFMONTH	0+	{ "%02d",	"%d",	"%2d",	"%02d" },+#define	PAD_FMT_SDAYOFMONTH	1+#define	PAD_FMT_SHMS		1+	{ "%2d",	"%d",	"%2d",	"%02d" },+#define	PAD_FMT_DAYOFYEAR	2+	{ "%03d",	"%d",	"%3d",	"%03d" },+#define	PAD_FMT_YEAR		3+	{ "%04d",	"%d",	"%4d",	"%04d" }+};++size_t+_patch_strftime_l(char * __restrict s, size_t maxsize, const char * __restrict format,+    const struct tm * __restrict t, _locale_t loc)+{+	char *	p;+	int	warn;++	tzset();+	warn = IN_NONE;+	p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, loc);+#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU+	if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {+		(void) fprintf_l(stderr, loc, "\n");+		if (format == NULL)+			(void) fputs("NULL strftime format ", stderr);+		else	(void) fprintf_l(stderr, loc, "strftime format \"%s\" ",+				format);+		(void) fputs("yields only two digits of years in ", stderr);+		if (warn == IN_SOME)+			(void) fputs("some locales", stderr);+		else if (warn == IN_THIS)+			(void) fputs("the current locale", stderr);+		else	(void) fputs("all locales", stderr);+		(void) fputs("\n", stderr);+	}+#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */+	if (p == s + maxsize)+		return (0);+	*p = '\0';+	return p - s;+}++size_t+_patch_strftime(char * __restrict s, size_t maxsize, const char * __restrict format,+    const struct tm * __restrict t)+{+#if HAVE__GET_CURRENT_LOCALE+	return _patch_strftime_l(s, maxsize, format, t, _get_current_locale());+#else+	return _patch_strftime_l(s, maxsize, format, t, _create_locale(LC_TIME, "C"));+#endif+}++static char *+_fmt(const char *format, const struct tm * const t, char *pt,+    const char * const ptlim, int *warnp, _locale_t loc)+{+	int Ealternative, Oalternative, PadIndex;+	const struct lc_time_T *tptr = &_C_time_locale;++	for ( ; *format; ++format) {+		if (*format == '%') {+			Ealternative = 0;+			Oalternative = 0;+			PadIndex	 = PAD_DEFAULT;+label:+			switch (*++format) {+			case '\0':+				--format;+				break;+			case 'A':+				pt = _add((t->tm_wday < 0 ||+					t->tm_wday >= DAYSPERWEEK) ?+					"?" : tptr->weekday[t->tm_wday],+					pt, ptlim);+				continue;+			case 'a':+				pt = _add((t->tm_wday < 0 ||+					t->tm_wday >= DAYSPERWEEK) ?+					"?" : tptr->wday[t->tm_wday],+					pt, ptlim);+				continue;+			case 'B':+				pt = _add((t->tm_mon < 0 ||+					t->tm_mon >= MONSPERYEAR) ?+					"?" : (Oalternative ? tptr->alt_month :+					tptr->month)[t->tm_mon],+					pt, ptlim);+				continue;+			case 'b':+			case 'h':+				pt = _add((t->tm_mon < 0 ||+					t->tm_mon >= MONSPERYEAR) ?+					"?" : tptr->mon[t->tm_mon],+					pt, ptlim);+				continue;+			case 'C':+				/*+				 * %C used to do a...+				 *	_fmt("%a %b %e %X %Y", t);+				 * ...whereas now POSIX 1003.2 calls for+				 * something completely different.+				 * (ado, 1993-05-24)+				 */+				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,+					pt, ptlim, loc);+				continue;+			case 'c':+				{+				int warn2 = IN_SOME;++				pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2, loc);+				if (warn2 == IN_ALL)+					warn2 = IN_THIS;+				if (warn2 > *warnp)+					*warnp = warn2;+				}+				continue;+			case 'D':+				pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, loc);+				continue;+			case 'd':+				pt = _conv(t->tm_mday,+					fmt_padding[PAD_FMT_DAYOFMONTH][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'E':+				if (Ealternative || Oalternative)+					break;+				Ealternative++;+				goto label;+			case 'O':+				/*+				 * C99 locale modifiers.+				 * The sequences+				 *	%Ec %EC %Ex %EX %Ey %EY+				 *	%Od %oe %OH %OI %Om %OM+				 *	%OS %Ou %OU %OV %Ow %OW %Oy+				 * are supposed to provide alternate+				 * representations.+				 *+				 * FreeBSD extension+				 *      %OB+				 */+				if (Ealternative || Oalternative)+					break;+				Oalternative++;+				goto label;+			case 'e':+				pt = _conv(t->tm_mday,+					fmt_padding[PAD_FMT_SDAYOFMONTH][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'F':+				pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, loc);+				continue;+			case 'H':+				pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_HMS][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'I':+				pt = _conv((t->tm_hour % 12) ?+					(t->tm_hour % 12) : 12,+					fmt_padding[PAD_FMT_HMS][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'j':+				pt = _conv(t->tm_yday + 1,+					fmt_padding[PAD_FMT_DAYOFYEAR][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'k':+				/*+				 * This used to be...+				 *	_conv(t->tm_hour % 12 ?+				 *		t->tm_hour % 12 : 12, 2, ' ');+				 * ...and has been changed to the below to+				 * match SunOS 4.1.1 and Arnold Robbins'+				 * strftime version 3.0. That is, "%k" and+				 * "%l" have been swapped.+				 * (ado, 1993-05-24)+				 */+				pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_SHMS][PadIndex],+					pt, ptlim, loc);+				continue;+#ifdef KITCHEN_SINK+			case 'K':+				/*+				** After all this time, still unclaimed!+				*/+				pt = _add("kitchen sink", pt, ptlim);+				continue;+#endif /* defined KITCHEN_SINK */+			case 'l':+				/*+				 * This used to be...+				 *	_conv(t->tm_hour, 2, ' ');+				 * ...and has been changed to the below to+				 * match SunOS 4.1.1 and Arnold Robbin's+				 * strftime version 3.0. That is, "%k" and+				 * "%l" have been swapped.+				 * (ado, 1993-05-24)+				 */+				pt = _conv((t->tm_hour % 12) ?+					(t->tm_hour % 12) : 12,+					fmt_padding[PAD_FMT_SHMS][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'M':+				pt = _conv(t->tm_min, fmt_padding[PAD_FMT_HMS][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'm':+				pt = _conv(t->tm_mon + 1,+					fmt_padding[PAD_FMT_MONTH][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'n':+				pt = _add("\n", pt, ptlim);+				continue;+			case 'p':+				pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?+					tptr->pm : tptr->am,+					pt, ptlim);+				continue;+			case 'R':+				pt = _fmt("%H:%M", t, pt, ptlim, warnp, loc);+				continue;+			case 'r':+				pt = _fmt(tptr->ampm_fmt, t, pt, ptlim,+					warnp, loc);+				continue;+			case 'S':+				pt = _conv(t->tm_sec, fmt_padding[PAD_FMT_HMS][PadIndex],+					pt, ptlim, loc);+				continue;+			case 's':+				{+					struct tm	tm;+					char		buf[INT_STRLEN_MAXIMUM(+								time_t) + 1];+					time_t		mkt;++					tm = *t;+					mkt = mktime(&tm);+					if (TYPE_SIGNED(time_t))+						(void) sprintf_l(buf, loc, "%lld", (long long)mkt);+					else+						(void) sprintf_l(buf, loc, "%llu", (unsigned long long)mkt);+					pt = _add(buf, pt, ptlim);+				}+				continue;+			case 'T':+				pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, loc);+				continue;+			case 't':+				pt = _add("\t", pt, ptlim);+				continue;+			case 'U':+				pt = _conv((t->tm_yday + DAYSPERWEEK -+					t->tm_wday) / DAYSPERWEEK,+					fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'u':+				/*+				 * From Arnold Robbins' strftime version 3.0:+				 * "ISO 8601: Weekday as a decimal number+				 * [1 (Monday) - 7]"+				 * (ado, 1993-05-24)+				 */+				pt = _conv((t->tm_wday == 0) ?+					DAYSPERWEEK : t->tm_wday,+					"%d", pt, ptlim, loc);+				continue;+			case 'V':	/* ISO 8601 week number */+			case 'G':	/* ISO 8601 year (four digits) */+			case 'g':	/* ISO 8601 year (two digits) */+/*+ * From Arnold Robbins' strftime version 3.0: "the week number of the+ * year (the first Monday as the first day of week 1) as a decimal number+ * (01-53)."+ * (ado, 1993-05-24)+ *+ * From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:+ * "Week 01 of a year is per definition the first week which has the+ * Thursday in this year, which is equivalent to the week which contains+ * the fourth day of January. In other words, the first week of a new year+ * is the week which has the majority of its days in the new year. Week 01+ * might also contain days from the previous year and the week before week+ * 01 of a year is the last week (52 or 53) of the previous year even if+ * it contains days from the new year. A week starts with Monday (day 1)+ * and ends with Sunday (day 7). For example, the first week of the year+ * 1997 lasts from 1996-12-30 to 1997-01-05..."+ * (ado, 1996-01-02)+ */+				{+					int	year;+					int	base;+					int	yday;+					int	wday;+					int	w;++					year = t->tm_year;+					base = TM_YEAR_BASE;+					yday = t->tm_yday;+					wday = t->tm_wday;+					for ( ; ; ) {+						int	len;+						int	bot;+						int	top;++						len = isleap_sum(year, base) ?+							DAYSPERLYEAR :+							DAYSPERNYEAR;+						/*+						 * What yday (-3 ... 3) does+						 * the ISO year begin on?+						 */+						bot = ((yday + 11 - wday) %+							DAYSPERWEEK) - 3;+						/*+						 * What yday does the NEXT+						 * ISO year begin on?+						 */+						top = bot -+							(len % DAYSPERWEEK);+						if (top < -3)+							top += DAYSPERWEEK;+						top += len;+						if (yday >= top) {+							++base;+							w = 1;+							break;+						}+						if (yday >= bot) {+							w = 1 + ((yday - bot) /+								DAYSPERWEEK);+							break;+						}+						--base;+						yday += isleap_sum(year, base) ?+							DAYSPERLYEAR :+							DAYSPERNYEAR;+					}+#ifdef XPG4_1994_04_09+					if ((w == 52 &&+						t->tm_mon == TM_JANUARY) ||+						(w == 1 &&+						t->tm_mon == TM_DECEMBER))+							w = 53;+#endif /* defined XPG4_1994_04_09 */+					if (*format == 'V')+						pt = _conv(w, fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],+							pt, ptlim, loc);+					else if (*format == 'g') {+						*warnp = IN_ALL;+						pt = _yconv(year, base, 0, 1,+							pt, ptlim, loc);+					} else	pt = _yconv(year, base, 1, 1,+							pt, ptlim, loc);+				}+				continue;+			case 'v':+				/*+				 * From Arnold Robbins' strftime version 3.0:+				 * "date as dd-bbb-YYYY"+				 * (ado, 1993-05-24)+				 */+				pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, loc);+				continue;+			case 'W':+				pt = _conv((t->tm_yday + DAYSPERWEEK -+					(t->tm_wday ?+					(t->tm_wday - 1) :+					(DAYSPERWEEK - 1))) / DAYSPERWEEK,+					fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],+					pt, ptlim, loc);+				continue;+			case 'w':+				pt = _conv(t->tm_wday, "%d", pt, ptlim, loc);+				continue;+			case 'X':+				pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp, loc);+				continue;+			case 'x':+				{+				int	warn2 = IN_SOME;++				pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2, loc);+				if (warn2 == IN_ALL)+					warn2 = IN_THIS;+				if (warn2 > *warnp)+					*warnp = warn2;+				}+				continue;+			case 'y':+				*warnp = IN_ALL;+				pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,+					pt, ptlim, loc);+				continue;+			case 'Y':+				pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,+					pt, ptlim, loc);+				continue;+			case 'Z':+#ifdef TM_ZONE+				if (t->TM_ZONE != NULL)+					pt = _add(t->TM_ZONE, pt, ptlim);+				else+#endif /* defined TM_ZONE */+				if (t->tm_isdst >= 0)+					pt = _add(tzname[t->tm_isdst != 0],+						pt, ptlim);+				/*+				 * C99 says that %Z must be replaced by the+				 * empty string if the time zone is not+				 * determinable.+				 */+				continue;+			case 'z':+				{+				int		diff;+				char const *	sign;++				if (t->tm_isdst < 0)+					continue;+#ifdef TM_GMTOFF+				diff = t->TM_GMTOFF;+#else /* !defined TM_GMTOFF */+				/*+				 * C99 says that the UTC offset must+				 * be computed by looking only at+				 * tm_isdst. This requirement is+				 * incorrect, since it means the code+				 * must rely on magic (in this case+				 * altzone and timezone), and the+				 * magic might not have the correct+				 * offset. Doing things correctly is+				 * tricky and requires disobeying C99;+				 * see GNU C strftime for details.+				 * For now, punt and conform to the+				 * standard, even though it's incorrect.+				 *+				 * C99 says that %z must be replaced by the+				 * empty string if the time zone is not+				 * determinable, so output nothing if the+				 * appropriate variables are not available.+				 */+				if (t->tm_isdst == 0)+					diff = -timezone;+				else+#ifdef ALTZONE+					diff = -altzone;+#else /* !defined ALTZONE */+					continue;+#endif /* !defined ALTZONE */+#endif /* !defined TM_GMTOFF */+				if (diff < 0) {+					sign = "-";+					diff = -diff;+				} else+					sign = "+";+				pt = _add(sign, pt, ptlim);+				diff /= SECSPERMIN;+				diff = (diff / MINSPERHOUR) * 100 ++					(diff % MINSPERHOUR);+				pt = _conv(diff,+					fmt_padding[PAD_FMT_YEAR][PadIndex],+					pt, ptlim, loc);+				}+				continue;+			case '+':+				pt = _fmt(tptr->date_fmt, t, pt, ptlim,+					warnp, loc);+				continue;+			case '-':+				if (PadIndex != PAD_DEFAULT)+					break;+				PadIndex = PAD_LESS;+				goto label;+			case '_':+				if (PadIndex != PAD_DEFAULT)+					break;+				PadIndex = PAD_SPACE;+				goto label;+			case '0':+				if (PadIndex != PAD_DEFAULT)+					break;+				PadIndex = PAD_ZERO;+				goto label;+			case '%':+			/*+			 * X311J/88-090 (4.12.3.5): if conversion char is+			 * undefined, behavior is undefined. Print out the+			 * character itself as printf(3) also does.+			 */+			default:+				break;+			}+		}+		if (pt == ptlim)+			break;+		*pt++ = *format;+	}+	return (pt);+}++static char *+_conv(const int n, const char * const format, char * const pt,+    const char * const ptlim, _locale_t  loc)+{+	char	buf[INT_STRLEN_MAXIMUM(int) + 1];++	(void) sprintf_l(buf, loc, format, n);+	return _add(buf, pt, ptlim);+}++static char *+_add(const char *str, char *pt, const char * const ptlim)+{+	while (pt < ptlim && (*pt = *str++) != '\0')+		++pt;+	return (pt);+}++/*+ * POSIX and the C Standard are unclear or inconsistent about+ * what %C and %y do if the year is negative or exceeds 9999.+ * Use the convention that %C concatenated with %y yields the+ * same output as %Y, and that %Y contains at least 4 bytes,+ * with more only if necessary.+ */++static char *+_yconv(const int a, const int b, const int convert_top, const int convert_yy,+    char *pt, const char * const ptlim, _locale_t  loc)+{+	register int	lead;+	register int	trail;++#define	DIVISOR	100+	trail = a % DIVISOR + b % DIVISOR;+	lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;+	trail %= DIVISOR;+	if (trail < 0 && lead > 0) {+		trail += DIVISOR;+		--lead;+	} else if (lead < 0 && trail > 0) {+		trail -= DIVISOR;+		++lead;+	}+	if (convert_top) {+		if (lead == 0 && trail < 0)+			pt = _add("-0", pt, ptlim);+		else	pt = _conv(lead, "%02d", pt, ptlim, loc);+	}+	if (convert_yy)+		pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt,+		     ptlim, loc);+	return (pt);+}
+ cbits/strptime.c view
@@ -0,0 +1,718 @@+/*-+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD+ *+ * Copyright (c) 2014 Gary Mills+ * Copyright 2011, Nexenta Systems, Inc.  All rights reserved.+ * Copyright (c) 1994 Powerdog Industries.  All rights reserved.+ *+ * Copyright (c) 2011 The FreeBSD Foundation+ * All rights reserved.+ * Portions of this software were developed by David Chisnall+ * under sponsorship from the FreeBSD Foundation.+ *+ * Redistribution and use in source and binary forms, with or without+ * modification, are permitted provided that the following conditions+ * are met:+ * 1. Redistributions of source code must retain the above copyright+ *    notice, this list of conditions and the following disclaimer.+ * 2. Redistributions in binary form must reproduce the above copyright+ *    notice, this list of conditions and the following disclaimer+ *    in the documentation and/or other materials provided with the+ *    distribution.+ *+ * THIS SOFTWARE IS PROVIDED BY POWERDOG INDUSTRIES ``AS IS'' AND ANY+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE POWERDOG INDUSTRIES BE+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+ *+ * The views and conclusions contained in the software and documentation+ * are those of the authors and should not be interpreted as representing+ * official policies, either expressed or implied, of Powerdog Industries.+ */++#include <sys/cdefs.h>++#include <time.h>+#include <ctype.h>+#include <errno.h>+#include <locale.h>+#include <stdlib.h>+#include <string.h>+#include <pthread.h>++#include "win_patch.h"++static char * _strptime(const char *, const char *, struct tm *, int *, _locale_t);++#define	asizeof(a)	(sizeof(a) / sizeof((a)[0]))++#define FLAG_NONE   (1 << 0)+#define FLAG_YEAR   (1 << 1)+#define FLAG_MONTH  (1 << 2)+#define FLAG_YDAY   (1 << 3)+#define FLAG_MDAY   (1 << 4)+#define FLAG_WDAY   (1 << 5)++/*+ * Calculate the week day of the first day of a year. Valid for+ * the Gregorian calendar, which began Sept 14, 1752 in the UK+ * and its colonies. Ref:+ * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week+ */++static int+first_wday_of(int year)+{+	return (((2 * (3 - (year / 100) % 4)) + (year % 100) ++		((year % 100) / 4) + (isleap(year) ? 6 : 0) + 1) % 7);+}++static char *+_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,+		_locale_t locale)+{+	char	c;+	const char *ptr;+	int	day_offset = -1, wday_offset;+	int week_offset;+	int	i, len;+	int flags;+	int Ealternative, Oalternative;+	int century, year;+	const struct lc_time_T *tptr = &_C_time_locale;+	static int start_of_month[2][13] = {+		{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},+		{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}+	};++	flags = FLAG_NONE;+	century = -1;+	year = -1;++	ptr = fmt;+	while (*ptr != 0) {+		c = *ptr++;++		if (c != '%') {+			if (isspace_l((unsigned char)c, locale))+				while (*buf != 0 && +				       isspace_l((unsigned char)*buf, locale))+					buf++;+			else if (c != *buf++)+				return (NULL);+			continue;+		}++		Ealternative = 0;+		Oalternative = 0;+label:+		c = *ptr++;+		switch (c) {+		case '%':+			if (*buf++ != '%')+				return (NULL);+			break;++		case '+':+			buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			flags |= FLAG_WDAY | FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;+			break;++		case 'C':+			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			/* XXX This will break for 3-digit centuries. */+			len = 2;+			for (i = 0; len && *buf != 0 &&+			     isdigit_l((unsigned char)*buf, locale); buf++) {+				i *= 10;+				i += *buf - '0';+				len--;+			}++			century = i;+			flags |= FLAG_YEAR;++			break;++		case 'c':+			buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			flags |= FLAG_WDAY | FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;+			break;++		case 'D':+			buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;+			break;++		case 'E':+			if (Ealternative || Oalternative)+				break;+			Ealternative++;+			goto label;++		case 'O':+			if (Ealternative || Oalternative)+				break;+			Oalternative++;+			goto label;++		case 'F':+			buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;+			break;++		case 'R':+			buf = _strptime(buf, "%H:%M", tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			break;++		case 'r':+			buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			break;++		case 'T':+			buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			break;++		case 'X':+			buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			break;++		case 'x':+			buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale);+			if (buf == NULL)+				return (NULL);+			flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;+			break;++		case 'j':+			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			len = 3;+			for (i = 0; len && *buf != 0 &&+			     isdigit_l((unsigned char)*buf, locale); buf++){+				i *= 10;+				i += *buf - '0';+				len--;+			}+			if (i < 1 || i > 366)+				return (NULL);++			tm->tm_yday = i - 1;+			flags |= FLAG_YDAY;++			break;++		case 'M':+		case 'S':+			if (*buf == 0 ||+				isspace_l((unsigned char)*buf, locale))+				break;++			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			len = 2;+			for (i = 0; len && *buf != 0 &&+				isdigit_l((unsigned char)*buf, locale); buf++){+				i *= 10;+				i += *buf - '0';+				len--;+			}++			if (c == 'M') {+				if (i > 59)+					return (NULL);+				tm->tm_min = i;+			} else {+				if (i > 60)+					return (NULL);+				tm->tm_sec = i;+			}++			break;++		case 'H':+		case 'I':+		case 'k':+		case 'l':+			/*+			 * %k and %l specifiers are documented as being+			 * blank-padded.  However, there is no harm in+			 * allowing zero-padding.+			 *+			 * XXX %k and %l specifiers may gobble one too many+			 * digits if used incorrectly.+			 */++			len = 2;+			if ((c == 'k' || c == 'l') &&+			    isblank_l((unsigned char)*buf, locale)) {+				buf++;+				len = 1;+			}++			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			for (i = 0; len && *buf != 0 &&+			     isdigit_l((unsigned char)*buf, locale); buf++) {+				i *= 10;+				i += *buf - '0';+				len--;+			}+			if (c == 'H' || c == 'k') {+				if (i > 23)+					return (NULL);+			} else if (i == 0 || i > 12)+				return (NULL);++			tm->tm_hour = i;++			break;++		case 'p':+			/*+			 * XXX This is bogus if parsed before hour-related+			 * specifiers.+			 */+			if (tm->tm_hour > 12)+				return (NULL);++			len = strlen(tptr->am);+			if (strncasecmp_l(buf, tptr->am, len, locale) == 0) {+				if (tm->tm_hour == 12)+					tm->tm_hour = 0;+				buf += len;+				break;+			}++			len = strlen(tptr->pm);+			if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) {+				if (tm->tm_hour != 12)+					tm->tm_hour += 12;+				buf += len;+				break;+			}++			return (NULL);++		case 'A':+		case 'a':+			for (i = 0; i < asizeof(tptr->weekday); i++) {+				len = strlen(tptr->weekday[i]);+				if (strncasecmp_l(buf, tptr->weekday[i],+						len, locale) == 0)+					break;+				len = strlen(tptr->wday[i]);+				if (strncasecmp_l(buf, tptr->wday[i],+						len, locale) == 0)+					break;+			}+			if (i == asizeof(tptr->weekday))+				return (NULL);++			buf += len;+			tm->tm_wday = i;+			flags |= FLAG_WDAY;+			break;++		case 'U':+		case 'W':+			/*+			 * XXX This is bogus, as we can not assume any valid+			 * information present in the tm structure at this+			 * point to calculate a real value, so just check the+			 * range for now.+			 */+			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			len = 2;+			for (i = 0; len && *buf != 0 &&+			     isdigit_l((unsigned char)*buf, locale); buf++) {+				i *= 10;+				i += *buf - '0';+				len--;+			}+			if (i > 53)+				return (NULL);++			if (c == 'U')+				day_offset = TM_SUNDAY;+			else+				day_offset = TM_MONDAY;+++			week_offset = i;++			break;++		case 'u':+		case 'w':+			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			i = *buf++ - '0';+			if (i < 0 || i > 7 || (c == 'u' && i < 1) ||+			    (c == 'w' && i > 6))+				return (NULL);++			tm->tm_wday = i % 7;+			flags |= FLAG_WDAY;++			break;++		case 'e':+			/*+			 * With %e format, our strftime(3) adds a blank space+			 * before single digits.+			 */+			if (*buf != 0 &&+			    isspace_l((unsigned char)*buf, locale))+			       buf++;+			/* FALLTHROUGH */+		case 'd':+			/*+			 * The %e specifier was once explicitly documented as+			 * not being zero-padded but was later changed to+			 * equivalent to %d.  There is no harm in allowing+			 * such padding.+			 *+			 * XXX The %e specifier may gobble one too many+			 * digits if used incorrectly.+			 */+			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			len = 2;+			for (i = 0; len && *buf != 0 &&+			     isdigit_l((unsigned char)*buf, locale); buf++) {+				i *= 10;+				i += *buf - '0';+				len--;+			}+			if (i == 0 || i > 31)+				return (NULL);++			tm->tm_mday = i;+			flags |= FLAG_MDAY;++			break;++		case 'B':+		case 'b':+		case 'h':+			for (i = 0; i < asizeof(tptr->month); i++) {+				if (Oalternative) {+					if (c == 'B') {+						len = strlen(tptr->alt_month[i]);+						if (strncasecmp_l(buf,+								tptr->alt_month[i],+								len, locale) == 0)+							break;+					}+				} else {+					len = strlen(tptr->month[i]);+					if (strncasecmp_l(buf, tptr->month[i],+							len, locale) == 0)+						break;+				}+			}+			/*+			 * Try the abbreviated month name if the full name+			 * wasn't found and Oalternative was not requested.+			 */+			if (i == asizeof(tptr->month) && !Oalternative) {+				for (i = 0; i < asizeof(tptr->month); i++) {+					len = strlen(tptr->mon[i]);+					if (strncasecmp_l(buf, tptr->mon[i],+							len, locale) == 0)+						break;+				}+			}+			if (i == asizeof(tptr->month))+				return (NULL);++			tm->tm_mon = i;+			buf += len;+			flags |= FLAG_MONTH;++			break;++		case 'm':+			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			len = 2;+			for (i = 0; len && *buf != 0 &&+			     isdigit_l((unsigned char)*buf, locale); buf++) {+				i *= 10;+				i += *buf - '0';+				len--;+			}+			if (i < 1 || i > 12)+				return (NULL);++			tm->tm_mon = i - 1;+			flags |= FLAG_MONTH;++			break;++		case 's':+			{+			char *cp;+			int sverrno;+			long long n;+			time_t t;++			sverrno = errno;+			errno = 0;+			n = strtoll_l(buf, &cp, 10, locale);+			if (errno == ERANGE || (long long)(t = n) != n) {+				errno = sverrno;+				return (NULL);+			}+			errno = sverrno;+			buf = cp;+			if (gmtime_r(&t, tm) == NULL)+				return (NULL);+			*GMTp = 1;+			flags |= FLAG_YDAY | FLAG_WDAY | FLAG_MONTH |+			    FLAG_MDAY | FLAG_YEAR;+			}+			break;++		case 'Y':+		case 'y':+			if (*buf == 0 ||+			    isspace_l((unsigned char)*buf, locale))+				break;++			if (!isdigit_l((unsigned char)*buf, locale))+				return (NULL);++			len = (c == 'Y') ? 4 : 2;+			for (i = 0; len && *buf != 0 &&+			     isdigit_l((unsigned char)*buf, locale); buf++) {+				i *= 10;+				i += *buf - '0';+				len--;+			}+			if (c == 'Y')+				century = i / 100;+			year = i % 100;++			flags |= FLAG_YEAR;++			break;++		case 'Z':+			{+			const char *cp;+			char *zonestr;++			for (cp = buf; *cp &&+			     isupper_l((unsigned char)*cp, locale); ++cp) {+				/*empty*/}+			if (cp - buf) {+				zonestr = alloca(cp - buf + 1);+				strncpy(zonestr, buf, cp - buf);+				zonestr[cp - buf] = '\0';+				tzset();+				if (0 == strcmp(zonestr, "GMT") ||+				    0 == strcmp(zonestr, "UTC")) {+				    *GMTp = 1;+				} else if (0 == strcmp(zonestr, tzname[0])) {+				    tm->tm_isdst = 0;+				} else if (0 == strcmp(zonestr, tzname[1])) {+				    tm->tm_isdst = 1;+				} else {+				    return (NULL);+				}+				buf += cp - buf;+			}+			}+			break;++		case 'z':+			{+			int sign = 1;++			if (*buf != '+') {+				if (*buf == '-')+					sign = -1;+				else+					return (NULL);+			}++			buf++;+			i = 0;+			for (len = 4; len > 0; len--) {+				if (isdigit_l((unsigned char)*buf, locale)) {+					i *= 10;+					i += *buf - '0';+					buf++;+				} else if (len == 2) {+					i *= 100;+					break;+				} else+					return (NULL);+			}++			if (i > 1400 || (sign == -1 && i > 1200) ||+			    (i % 100) >= 60)+				return (NULL);+			tm->tm_hour -= sign * (i / 100);+			tm->tm_min  -= sign * (i % 100);+			*GMTp = 1;+			}+			break;++		case 'n':+		case 't':+			while (isspace_l((unsigned char)*buf, locale))+				buf++;+			break;++		default:+			return (NULL);+		}+	}++	if (century != -1 || year != -1) {+		if (year == -1)+			year = 0;+		if (century == -1) {+			if (year < 69)+				year += 100;+		} else+			year += century * 100 - TM_YEAR_BASE;+		tm->tm_year = year;+	}++	if (!(flags & FLAG_YDAY) && (flags & FLAG_YEAR)) {+		if ((flags & (FLAG_MONTH | FLAG_MDAY)) ==+		    (FLAG_MONTH | FLAG_MDAY)) {+			tm->tm_yday = start_of_month[isleap(tm->tm_year ++			    TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1);+			flags |= FLAG_YDAY;+		} else if (day_offset != -1) {+			int tmpwday, tmpyday, fwo;++			fwo = first_wday_of(tm->tm_year + TM_YEAR_BASE);+			/* No incomplete week (week 0). */+			if (week_offset == 0 && fwo == day_offset)+				return (NULL);++			/* Set the date to the first Sunday (or Monday)+			 * of the specified week of the year.+			 */+			tmpwday = (flags & FLAG_WDAY) ? tm->tm_wday :+			    day_offset;+			tmpyday = (7 - fwo + day_offset) % 7 ++			    (week_offset - 1) * 7 ++			    (tmpwday - day_offset + 7) % 7;+			/* Impossible yday for incomplete week (week 0). */+			if (tmpyday < 0) {+				if (flags & FLAG_WDAY)+					return (NULL);+				tmpyday = 0;+			}+			tm->tm_yday = tmpyday;+			flags |= FLAG_YDAY;+		}+	}++	if ((flags & (FLAG_YEAR | FLAG_YDAY)) == (FLAG_YEAR | FLAG_YDAY)) {+		if (!(flags & FLAG_MONTH)) {+			i = 0;+			while (tm->tm_yday >=+			    start_of_month[isleap(tm->tm_year ++			    TM_YEAR_BASE)][i])+				i++;+			if (i > 12) {+				i = 1;+				tm->tm_yday -=+				    start_of_month[isleap(tm->tm_year ++				    TM_YEAR_BASE)][12];+				tm->tm_year++;+			}+			tm->tm_mon = i - 1;+			flags |= FLAG_MONTH;+		}+		if (!(flags & FLAG_MDAY)) {+			tm->tm_mday = tm->tm_yday -+			    start_of_month[isleap(tm->tm_year + TM_YEAR_BASE)]+			    [tm->tm_mon] + 1;+			flags |= FLAG_MDAY;+		}+		if (!(flags & FLAG_WDAY)) {+			i = 0;+			wday_offset = first_wday_of(tm->tm_year);+			while (i++ <= tm->tm_yday) {+				if (wday_offset++ >= 6)+					wday_offset = 0;+			}+			tm->tm_wday = wday_offset;+			flags |= FLAG_WDAY;+		}+	}++	return ((char *)buf);+}++char *+strptime_l(const char * __restrict buf, const char * __restrict fmt,+    struct tm * __restrict tm, _locale_t loc)+{+	char *ret;+	int gmt;+	// FIX_LOCALE(loc);++	gmt = 0;+	ret = _strptime(buf, fmt, tm, &gmt, loc);+	if (ret && gmt) {+		time_t t = timegm(tm);++		localtime_s(tm, &t);+	}++	return (ret);+}++char *+strptime(const char * __restrict buf, const char * __restrict fmt,+    struct tm * __restrict tm)+{+#if HAVE__GET_CURRENT_LOCALE+	return strptime_l(buf, fmt, tm, _get_current_locale());+#else+	return strptime_l(buf, fmt, tm, _create_locale(LC_TIME, "C"));+#endif+}
+ cbits/win_patch.c view
@@ -0,0 +1,119 @@+#include "win_patch.h"++#if !HAVE_STRTOL_L+long strtol_l(const char *nptr, char **endptr, int base, _locale_t locale) {+    return strtol(nptr, endptr, base);+}+#endif++#if !HAVE_STRTOLL_L+long long strtoll_l(const char *nptr, char **endptr, int base, _locale_t locale) {+    return strtoll(nptr, endptr, base);+}+#endif++inline int isblank_l( int c, _locale_t _loc)+{+    return ( c == ' ' || c == '\t' );+}++inline int strncasecmp_l(const char *s1, const char *s2, int len, _locale_t _loc) {+    return strncasecmp(s1, s2, len);+}++inline struct tm *gmtime_r(const time_t *_time_t, struct tm *_tm) {+    errno_t err = gmtime_s(_tm, _time_t);+    if (err) {+        return NULL;+    }+    return _tm;+}++inline struct tm *localtime_r(const time_t *_time_t, struct tm *_tm) {+    errno_t err = localtime_s(_tm, _time_t);+    if (err) {+        return NULL;+    }+    return _tm;+}++const struct lc_time_T   _C_time_locale = {+    {+        "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"+    },++    /* X_fmt */+    "%H:%M:%S",++    /*+     * x_fmt+     * Since the C language standard calls for+     * "date, using locale's date format," anything goes.+     * Using just numbers (as here) makes Quakers happier;+     * it's also compatible with SVR4.+     */+    "%m/%d/%y",++    /*+     * c_fmt+     */+    "%a %b %e %H:%M:%S %Y",++    /* am */+    "AM",++    /* pm */+    "PM",++    /* date_fmt */+    "%a %b %e %H:%M:%S %Z %Y",+    +    /* alt_month+     * Standalone months forms for %OB+     */+    {+        "January", "February", "March", "April", "May", "June",+        "July", "August", "September", "October", "November", "December"+    },++    /* md_order+     * Month / day order in dates+     */+    "md",++    /* ampm_fmt+     * To determine 12-hour clock format time (empty, if N/A)+     */+    "%I:%M:%S %p"+};+++int _patch_setenv(const char *var, const char *val, int ovr) {+    BOOL b = SetEnvironmentVariableA(var, val);+    if (b) {+        return 0;+    } else {+        return 1;+    }+}++int _patch_unsetenv(const char *name) {+    int len = strlen(name);+    char *sname = (char *)malloc(len + 2);+    strcpy(sname, name);+    sname[len] = '=';+    sname[len + 1] = '\0';+    int r = _putenv(sname);+    free(sname);+    return r;+}
configure view
@@ -3304,6 +3304,50 @@ fi done +for ac_func in _mkgmtime+do :+  ac_fn_c_check_func "$LINENO" "_mkgmtime" "ac_cv_func__mkgmtime"+if test "x$ac_cv_func__mkgmtime" = xyes; then :+  cat >>confdefs.h <<_ACEOF+#define HAVE__MKGMTIME 1+_ACEOF++fi+done++for ac_func in _get_current_locale+do :+  ac_fn_c_check_func "$LINENO" "_get_current_locale" "ac_cv_func__get_current_locale"+if test "x$ac_cv_func__get_current_locale" = xyes; then :+  cat >>confdefs.h <<_ACEOF+#define HAVE__GET_CURRENT_LOCALE 1+_ACEOF++fi+done++for ac_func in strtol_l+do :+  ac_fn_c_check_func "$LINENO" "strtol_l" "ac_cv_func_strtol_l"+if test "x$ac_cv_func_strtol_l" = xyes; then :+  cat >>confdefs.h <<_ACEOF+#define HAVE_STRTOL_L 1+_ACEOF++fi+done++for ac_func in strtoll_l+do :+  ac_fn_c_check_func "$LINENO" "strtoll_l" "ac_cv_func_strtoll_l"+if test "x$ac_cv_func_strtoll_l" = xyes; then :+  cat >>confdefs.h <<_ACEOF+#define HAVE_STRTOLL_L 1+_ACEOF++fi+done+  host=`uname -a` case $host in
configure.ac view
@@ -8,6 +8,10 @@  AC_CHECK_FUNCS(strptime_l) AC_CHECK_FUNCS(timegm)+AC_CHECK_FUNCS(_mkgmtime)+AC_CHECK_FUNCS(_get_current_locale)+AC_CHECK_FUNCS(strtol_l)+AC_CHECK_FUNCS(strtoll_l)  host=`uname -a` case $host in
unix-time.cabal view
@@ -1,5 +1,5 @@ Name:                   unix-time-Version:                0.3.8+Version:                0.4.0 Author:                 Kazu Yamamoto <kazu@iij.ad.jp> Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp> License:                BSD3@@ -27,6 +27,10 @@                       , old-time                       , binary   C-Sources:            cbits/conv.c+  if os(windows)+    C-Sources:          cbits/strftime.c+                      , cbits/strptime.c+                      , cbits/win_patch.c   include-dirs:         cbits  Test-Suite doctest