From fe0621bafd21acaf9909cb2f8ea65fa56560faed Mon Sep 17 00:00:00 2001
From: Lukas Fleischer <lfleischer@calcurse.org>
Date: Wed, 10 Feb 2016 08:06:37 +0100
Subject: Allow decimals in durations

Parse durations containing decimal numbers (such as "1.5h") gracefully.

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

(limited to 'src')

diff --git a/src/utils.c b/src/utils.c
index a6ccec9..4ce9364 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -907,7 +907,7 @@ int parse_duration(const char *string, unsigned *duration)
 	} state = STATE_INITIAL;
 
 	const char *p;
-	unsigned in = 0;
+	unsigned in = 0, frac = 0, denom = 1;
 	unsigned dur = 0;
 
 	if (!string || *string == '\0')
@@ -919,20 +919,26 @@ int parse_duration(const char *string, unsigned *duration)
 			return 0;
 		} else if ((*p >= '0') && (*p <= '9')) {
 			in = in * 10 + (int)(*p - '0');
+			if (frac)
+				denom *= 10;
+		} else if (*p == '.') {
+			if (frac)
+				return 0;
+			frac++;
 		} else {
 			switch (state) {
 			case STATE_INITIAL:
 				if (*p == ':') {
-					dur += in * HOURINMIN;
+					dur += in * HOURINMIN / denom;
 					state = STATE_HHMM_MM;
 				} else if (*p == 'd') {
-					dur += in * DAYINMIN;
+					dur += in * DAYINMIN / denom;
 					state = STATE_DDHHMM_HH;
 				} else if (*p == 'h') {
-					dur += in * HOURINMIN;
+					dur += in * HOURINMIN / denom;
 					state = STATE_DDHHMM_MM;
 				} else if (*p == 'm') {
-					dur += in;
+					dur += in / denom;
 					state = STATE_DONE;
 				} else {
 					return 0;
@@ -940,10 +946,10 @@ int parse_duration(const char *string, unsigned *duration)
 				break;
 			case STATE_DDHHMM_HH:
 				if (*p == 'h') {
-					dur += in * HOURINMIN;
+					dur += in * HOURINMIN / denom;
 					state = STATE_DDHHMM_MM;
 				} else if (*p == 'm') {
-					dur += in;
+					dur += in / denom;
 					state = STATE_DONE;
 				} else {
 					return 0;
@@ -951,7 +957,7 @@ int parse_duration(const char *string, unsigned *duration)
 				break;
 			case STATE_DDHHMM_MM:
 				if (*p == 'm') {
-					dur += in;
+					dur += in / denom;
 					state = STATE_DONE;
 				} else {
 					return 0;
@@ -964,7 +970,8 @@ int parse_duration(const char *string, unsigned *duration)
 				break;
 			}
 
-			in = 0;
+			in = frac = 0;
+			denom = 1;
 		}
 	}
 
-- 
cgit v1.2.3-70-g09d2