NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/50009: strptime small enhancement



>Number:         50009
>Category:       lib
>Synopsis:       strptime small enhancement
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    lib-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jun 28 19:50:00 +0000 2015
>Originator:     David Carlier
>Release:        -current
>Organization:
>Environment:
NetBSD 7.99.19 (GENERIC) amd64
>Description:
Hi,

It is a small strptime libc function enhancement to fill more fields in more use cases like way, may, month ... to make it more equal to other BSDs.


>How-To-Repeat:

>Fix:
Index: time/private.h
===================================================================
RCS file: /cvsroot/src/lib/libc/time/private.h,v
retrieving revision 1.42
diff -u -r1.42 private.h
--- time/private.h	22 Jun 2015 17:43:23 -0000	1.42
+++ time/private.h	28 Jun 2015 19:32:32 -0000
@@ -558,6 +558,10 @@
 char *ctime_r(time_t const *, char *);
 #endif /* HAVE_INCOMPATIBLE_CTIME_R */
 
+#ifndef ISLEAPYEAR
+#define ISLEAPYEAR(y) ((y % 400) == 0 && (y % 4) == 0 && (y % 100) != 0)
+#endif
+
 #ifndef YEARSPERREPEAT
 #define YEARSPERREPEAT		400	/* years before a Gregorian repeat */
 #endif /* !defined YEARSPERREPEAT */
Index: time/strptime.c
===================================================================
RCS file: /cvsroot/src/lib/libc/time/strptime.c,v
retrieving revision 1.39
diff -u -r1.39 strptime.c
--- time/strptime.c	6 Apr 2015 14:38:22 -0000	1.39
+++ time/strptime.c	28 Jun 2015 19:32:32 -0000
@@ -60,6 +60,12 @@
 #define ALT_O			0x02
 #define	LEGAL_ALT(x)		{ if (alt_format & ~(x)) return NULL; }
 
+#define	FLAG_YEAR	(1 << 0)
+#define	FLAG_MTH	(1 << 1)
+#define	FLAG_YDAY	(1 << 2)
+#define	FLAG_MDAY	(1 << 3)
+#define	FLAG_WDAY	(1 << 4)
+
 static char gmt[] = { "GMT" };
 static char utc[] = { "UTC" };
 /* RFC-822/RFC-2822 */
@@ -74,6 +80,15 @@
 static const u_char *find_string(const u_char *, int *, const char * const *,
 	const char * const *, int);
 
+static const int mths_per_yr_kind[2][12] = {
+	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int mths_code[12] = {
+	0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5
+};
+
 char *
 strptime(const char *buf, const char *fmt, struct tm *tm)
 {
@@ -85,7 +100,7 @@
 {
 	unsigned char c;
 	const unsigned char *bp, *ep;
-	int alt_format, i, split_year = 0, neg = 0, offs;
+	int alt_format, i, split_year = 0, neg = 0, flags = 0, offs;
 	const char *new_fmt;
 
 	bp = (const u_char *)buf;
@@ -180,6 +195,7 @@
 			bp = find_string(bp, &tm->tm_wday,
 			    _TIME_LOCALE(loc)->day, _TIME_LOCALE(loc)->abday, 7);
 			LEGAL_ALT(0);
+			flags |= FLAG_WDAY;
 			continue;
 
 		case 'B':	/* The month, using the locale's form. */
@@ -207,6 +223,7 @@
 		case 'e':
 			bp = conv_num(bp, &tm->tm_mday, 1, 31);
 			LEGAL_ALT(ALT_O);
+			flags |= FLAG_MDAY;
 			continue;
 
 		case 'k':	/* The hour (24-hour clock representation). */
@@ -232,6 +249,7 @@
 			bp = conv_num(bp, &i, 1, 366);
 			tm->tm_yday = i - 1;
 			LEGAL_ALT(0);
+			flags |= FLAG_YDAY;
 			continue;
 
 		case 'M':	/* The minute. */
@@ -244,6 +262,7 @@
 			bp = conv_num(bp, &i, 1, 12);
 			tm->tm_mon = i - 1;
 			LEGAL_ALT(ALT_O);
+			flags |= FLAG_MTH;
 			continue;
 
 		case 'p':	/* The locale's equivalent of AM/PM. */
@@ -305,12 +324,14 @@
 		case 'w':	/* The day of week, beginning on sunday. */
 			bp = conv_num(bp, &tm->tm_wday, 0, 6);
 			LEGAL_ALT(ALT_O);
+			flags |= FLAG_WDAY;
 			continue;
 
 		case 'u':	/* The day of week, monday = 1. */
 			bp = conv_num(bp, &i, 1, 7);
 			tm->tm_wday = i % 7;
 			LEGAL_ALT(ALT_O);
+			flags |= FLAG_WDAY;
 			continue;
 
 		case 'g':	/* The year corresponding to the ISO week
@@ -336,6 +357,7 @@
 			bp = conv_num(bp, &i, 0, 9999);
 			tm->tm_year = i - TM_YEAR_BASE;
 			LEGAL_ALT(ALT_E);
+			flags |= FLAG_YEAR;
 			continue;
 
 		case 'y':	/* The year within 100 years of the epoch. */
@@ -529,6 +551,60 @@
 		}
 	}
 
+	/**
+	 * Post processing of potential additional flags
+	 */
+	if (flags & FLAG_YEAR) {
+		int yr = 1900 + tm->tm_year;
+		const int *mths_yr = mths_per_yr_kind[ISLEAPYEAR(yr)];
+		if (!(flags & FLAG_YDAY)) {
+			if (flags & FLAG_MTH && flags & FLAG_MDAY) {
+				tm->tm_yday = tm->tm_mday - 1;
+				i = 0;
+				while (i < tm->tm_mon) {
+					tm->tm_yday += mths_yr[i];
+					i ++;
+				}
+
+				flags |= FLAG_YDAY;
+			}
+		}
+		if (flags & FLAG_YDAY) {
+			int d = tm->tm_yday;
+			if (!(flags & FLAG_MTH)) {
+				tm->tm_mon = 0;
+				i = 0;
+				while (i < 12) {
+					d -= mths_yr[i++];
+					if (d <= mths_yr[i])
+						break;
+				}
+				
+				tm->tm_mon = i;
+			}
+			if (!(flags & FLAG_MDAY))
+				tm->tm_mday = d + 1;
+			if (!(flags & FLAG_WDAY)) {
+				tm->tm_wday = tm->tm_mday / 7;
+			}
+		}
+		if (!(flags & FLAG_WDAY)) {
+			static const int centuries[4] = {
+				6, 4, 2, 0
+			};
+			int byear = ((int) yr & ~1) / 100;
+			int century = centuries[byear % 4];
+			int wday = 0;
+			
+			wday = mths_code[tm->tm_mon] + tm->tm_mday;
+			if (ISLEAPYEAR(yr) || tm->tm_mon < 2)
+				wday --;
+			wday =	(wday + tm->tm_year + (tm->tm_year / 4) + century) % 7;
+			
+			tm->tm_wday = wday > 4 ? 0 : wday;
+		}
+	}
+
 	return __UNCONST(bp);
 }
 



Home | Main Index | Thread Index | Old Index