Module Name:    src
Committed By:   christos
Date:           Mon Dec  7 20:55:49 UTC 2015

Modified Files:
        src/lib/libutil: parsedate.3 parsedate.y

Log Message:
- Add support for "midnight" "noon", dawn etc.
- Add validation to date/time strings by checking that mktime did not change
  the fields of struct tm from the ones requested
- Allow the format "year monthname day".
>From kre


To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/lib/libutil/parsedate.3
cvs rdiff -u -r1.22 -r1.23 src/lib/libutil/parsedate.y

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libutil/parsedate.3
diff -u src/lib/libutil/parsedate.3:1.17 src/lib/libutil/parsedate.3:1.18
--- src/lib/libutil/parsedate.3:1.17	Thu Nov 26 04:48:21 2015
+++ src/lib/libutil/parsedate.3	Mon Dec  7 15:55:49 2015
@@ -1,4 +1,4 @@
-.\"     $NetBSD: parsedate.3,v 1.17 2015/11/26 09:48:21 wiz Exp $
+.\"     $NetBSD: parsedate.3,v 1.18 2015/12/07 20:55:49 christos Exp $
 .\"
 .\" Copyright (c) 2006 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd November 25, 2015
+.Dd December 7, 2015
 .Dt PARSEDATE 3
 .Os
 .Sh NAME
@@ -106,7 +106,14 @@ The following words are recognized in En
 .Dv AM ,
 .Dv PM ,
 .Dv a.m. ,
-.Dv p.m.
+.Dv p.m. ,
+.Dv midnight ,
+.Dv mn ,
+.Dv noon ,
+.Dv dawn ,
+.Dv sunup ,
+.Dv sunset ,
+.Dv sundown .
 .Pp
 The months:
 .Dv january ,
@@ -229,7 +236,7 @@ An ISO-8601 date.
 The year in an ISO-8601 date is always taken literally,
 so this is the year 69, not 2069.
 .It 10/1/2000
-October 10, 2000; the common US format.
+October 1, 2000; the common, but bizarre, US format.
 .It 20 Jun 1994
 .It 23jun2001
 .It 1-sep-06
@@ -253,6 +260,7 @@ As well as times:
 .It 12:11:01.000012
 .It 12:21-0500
 .El
+Fractions of seconds (after a decimal point) are parsed, but ignored.
 .Pp
 Relative items are also supported:
 .Bl -tag -compact -width "this thursday"

Index: src/lib/libutil/parsedate.y
diff -u src/lib/libutil/parsedate.y:1.22 src/lib/libutil/parsedate.y:1.23
--- src/lib/libutil/parsedate.y:1.22	Sun Dec  6 09:43:59 2015
+++ src/lib/libutil/parsedate.y	Mon Dec  7 15:55:49 2015
@@ -14,7 +14,7 @@
 
 #include <sys/cdefs.h>
 #ifdef __RCSID
-__RCSID("$NetBSD: parsedate.y,v 1.22 2015/12/06 14:43:59 christos Exp $");
+__RCSID("$NetBSD: parsedate.y,v 1.23 2015/12/07 20:55:49 christos Exp $");
 #endif
 
 #include <stdio.h>
@@ -99,10 +99,10 @@ struct dateinfo {
 }
 
 %token	tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
-%token	tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST AT_SIGN
+%token	tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST AT_SIGN tTIME
 
 %type	<Number>	tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
-%type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type	<Number>	tSEC_UNIT tSNUMBER tUNUMBER tZONE tTIME
 %type	<Meridian>	tMERIDIAN o_merid
 
 %parse-param	{ struct dateinfo *param }
@@ -215,6 +215,15 @@ time	: tUNUMBER tMERIDIAN {
 	    param->yyMeridian = MER24;
 /* XXX: Do nothing with millis */
 	}
+	| tTIME {
+	    param->yyHour = $1;
+	    param->yyMinutes = 0;
+	    param->yySeconds = 0;
+	    param->yyMeridian = MER24;
+	    /* Tues midnight --> Weds 00:00, midnight Tues -> Tues 00:00 */
+	    if ($1 == 0 && param->yyHaveDay)
+	        param->yyDayNumber++;
+	}
 	;
 
 time_numericzone : tUNUMBER ':' tUNUMBER tSNUMBER {
@@ -306,8 +315,13 @@ date	: tUNUMBER '/' tUNUMBER {
 	}
 	| tUNUMBER tMONTH tUNUMBER {
 	    param->yyMonth = $2;
-	    param->yyDay = $1;
-	    param->yyYear = $3;
+	    if ($1 < 35) {
+	        param->yyDay = $1;
+	        param->yyYear = $3;
+	    } else {
+	        param->yyDay = $3;
+	        param->yyYear = $1;
+	    }
 	}
 	;
 
@@ -589,6 +603,17 @@ static const TABLE MilitaryTable[] = {
     { NULL,	0,	0 }
 };
 
+static const TABLE TimeNames[] = {
+    { "midnight",	tTIME,		 0 },
+    { "mn",		tTIME,		 0 },
+    { "noon",		tTIME,		12 },
+    { "dawn",		tTIME,		 6 },
+    { "sunup",		tTIME,		 6 },
+    { "sunset",		tTIME,		18 },
+    { "sundown",	tTIME,		18 },
+    { NULL,		0,		 0 }
+};
+
 
 
 
@@ -635,6 +660,7 @@ Convert(
 )
 {
     struct tm tm = {.tm_sec = 0};
+    struct tm otm;
     time_t result;
 
     tm.tm_sec = Seconds;
@@ -673,6 +699,15 @@ Convert(
     fprintf(stderr, " %s", ctime(&result));
 #endif
 
+#define	TM_NE(fld) (otm.tm_ ## fld != tm.tm_ ## fld)
+    if (TM_NE(year) || TM_NE(mon) || TM_NE(mday) ||
+	TM_NE(hour) || TM_NE(min) || TM_NE(sec)) {
+	    /* mktime() "corrected" our tm, so it must have been invalid */
+	    result = -1;
+	    errno = EAGAIN;
+    }
+#undef	TM_NE
+
     return result;
 }
 
@@ -800,6 +835,12 @@ LookupWord(YYSTYPE *yylval, char *buff)
     if (strcmp(buff, "dst") == 0) 
 	return tDST;
 
+    for (tp = TimeNames; tp->name; tp++)
+	if (strcmp(buff, tp->name) == 0) {
+	    yylval->Number = tp->value;
+	    return tp->type;
+	}
+
     for (tp = UnitsTable; tp->name; tp++)
 	if (strcmp(buff, tp->name) == 0) {
 	    yylval->Number = tp->value;

Reply via email to