From 7f448ee8cd8e5031ccc48604af2857bde94b0bae Mon Sep 17 00:00:00 2001
From: Lars Henriksen <LarsHenriksen@get2net.dk>
Date: Sat, 2 Jun 2018 21:53:39 +0200
Subject: Minor merge adjustments

Comments inserted.

Slightly different implementations of parse_time() and parse_datetime().

Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
---
 src/utils.c | 79 +++++++++++++++++++++++++++++++++----------------------------
 1 file changed, 43 insertions(+), 36 deletions(-)

(limited to 'src')

diff --git a/src/utils.c b/src/utils.c
index 0690d4e..4758e0f 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -938,6 +938,13 @@ parse_date_interactive(const char *datestr, int *year, int *month, int *day)
  * Convert a date duration string into a number of days.
  * If start is non-zero, the final end time is validated.
  *
+ * Allowed formats in lenient BNF:
+ * <duration> ::= <days> | <period>
+ * <period>   ::= [ <weeks>w ][ <days>d ]
+ * Notes:
+ *            <days> and <weeks> are any integer >= 0.
+ *            <period> must have at least one non-terminal.
+ *
  * Returns 1 on success and 0 on failure.
  */
 int parse_date_duration(const char *string, unsigned *days, time_t start)
@@ -996,10 +1003,8 @@ int parse_date_duration(const char *string, unsigned *days, time_t start)
 			denom = 1;
 		}
 	}
-
 	if (state == STATE_DONE && in > 0)
 		return 0;
-
 	dur += in;
 	if (start) {
 		/* wanted: start = start + dur * DAYINSEC */
@@ -1013,7 +1018,6 @@ int parse_date_duration(const char *string, unsigned *days, time_t start)
 			return 0;
 	}
 	*days = dur;
-
 	return 1;
 }
 
@@ -1027,7 +1031,9 @@ int check_time(unsigned hours, unsigned minutes)
 
 /*
  * Converts a time string into hours and minutes. Short forms like "23:"
- * (23:00) or ":45" (0:45) are allowed.
+ * (23:00) or ":45" (0:45) are allowed as well as "2345". Note: the latter
+ * clashes with date formats 0001 .. 0031 and must be picked up before
+ * dates when parsing in parse_datetime.
  *
  * Returns 1 on success and 0 on failure.
  */
@@ -1044,14 +1050,18 @@ int parse_time(const char *string, unsigned *hour, unsigned *minute)
 		if (*p == ':') {
 			if ((++n) > 1)
 				return 0;
-		} else if ((*p >= '0') && (*p <= '9')) {
-			if ((n == 0) && (p == (string + 2)) && *(p + 1))
-				n++;
-			in[n] = in[n] * 10 + (int)(*p - '0');
+		} else if (isdigit(*p)) {
+			in[n] = in[n] * 10 + *p - '0';
 		} else {
 			return 0;
 		}
 	}
+	/* 24-hour format without ':' (hhmm)? */
+	if (n == 0 && strlen(string) == 4) {
+		in[1] = in[0] % 100;
+		in[0] = in[0] / 100;
+		n = 1;
+	}
 
 	if (n != 1 || !check_time(in[0], in[1]))
 		return 0;
@@ -1065,13 +1075,15 @@ int parse_time(const char *string, unsigned *hour, unsigned *minute)
  * Converts a duration string into minutes.
  * If start time is non-zero, the final end time is validated.
  *
- * Allowed formats (noted as regular expressions):
- *
- * - \d*:\d*
- * - (\d*m|\d*h(|\d*m)|\d*d(|\d*m|\d*h(|\d*m)))
- * - \d+
- *
- * "\d" is used as a placeholder for "(0|1|2|3|4|5|6|7|8|9)".
+ * Allowed formats in lenient BNF:
+ * <duration> ::= <minutes> | <time> | <period>
+ * <time>     ::= <hours>:<min>
+ * <period>   ::= [ <days>d ][ <hours>h ][ <minutes>m ]
+ * <min>      ::= integer in the range 0-59
+ * Notes:
+ *            <days>, <hours> and <minutes> are any sequence of
+ *	      the characters 1,2,..,9,0.
+ *            <period> must have at least one non-terminal.
  *
  * Returns 1 on success and 0 on failure.
  */
@@ -1144,7 +1156,6 @@ int parse_duration(const char *string, unsigned *duration, time_t start)
 				break;
 			case STATE_HHMM_MM:
 				return 0;
-				break;
 			default:
 				break;
 			}
@@ -1154,8 +1165,7 @@ int parse_duration(const char *string, unsigned *duration, time_t start)
 		}
 	}
 	if ((state == STATE_HHMM_MM && in >= HOURINMIN) ||
-	    ((state == STATE_DDHHMM_HH || state == STATE_DDHHMM_MM)
-	     && in > 0))
+	    ((state == STATE_DDHHMM_HH || state == STATE_DDHHMM_MM) && in > 0))
 		return 0;
 	dur += in;
 	if (start) {
@@ -1171,7 +1181,6 @@ int parse_duration(const char *string, unsigned *duration, time_t start)
 			return 0;
 	}
 	*duration = dur;
-
 	return 1;
 }
 
@@ -1192,37 +1201,35 @@ int parse_duration(const char *string, unsigned *duration, time_t start)
  */
 int parse_datetime(const char *string, time_t *ts, time_t dur)
 {
-	char *t = mem_strdup(string);
-	char *p = strchr(t, ' ');
-
-	unsigned int hour, minute;
+	unsigned hour, minute;
 	int year, month, day;
-	struct date new_date;
 	int ret = 0;
 
-	if (p) {
-		*p = '\0';
-		if (parse_date_interactive(t, &year, &month, &day) &&
-		    parse_time(p + 1, &hour, &minute)) {
+	char *d = mem_strdup(string);
+	/* Split into date and time, if possible. */
+	char *t = strchr(d, ' ');
+	if (t)
+		*t++ = '\0';
+	if (t) {
+		if (parse_date_interactive(d, &year, &month, &day) &&
+	            parse_time(t, &hour, &minute)) {
 			ret |= PARSE_DATETIME_HAS_DATE |
 			       PARSE_DATETIME_HAS_TIME;
 		}
-	} else if (parse_time(t, &hour, &minute)) {
+	/* Time before date, see comments in parse_time(). */
+	} else if (parse_time(d, &hour, &minute)) {
 		ret |= PARSE_DATETIME_HAS_TIME;
-	} else if (parse_date_interactive(t, &year, &month, &day)) {
+	} else if (parse_date_interactive(d, &year, &month, &day)) {
 		ret |= PARSE_DATETIME_HAS_DATE;
 	}
-
 	if (ret & PARSE_DATETIME_HAS_DATE) {
-		new_date.dd = day;
-		new_date.mm = month;
-		new_date.yyyy = year;
-		*ts = date2sec(new_date, 0, 0) + get_item_time(*ts);
+		struct date date = { day , month, year };
+		*ts = date2sec(date, 0, 0) + get_item_time(*ts);
 	}
 	if (ret & PARSE_DATETIME_HAS_TIME)
 		*ts = update_time_in_date(*ts, hour, minute);
+	mem_free(d);
 
-	mem_free(t);
 	/* Is the resulting time a valid (start or end) time? */
 	if (!check_sec(ts))
 		return 0;
-- 
cgit v1.2.3-70-g09d2