about summary refs log tree commit diff
path: root/lr.c
diff options
context:
space:
mode:
authorChristian Neukirchen <chneukirchen@gmail.com>2015-12-27 10:32:10 +0100
committerChristian Neukirchen <chneukirchen@gmail.com>2015-12-27 10:32:10 +0100
commit481cfb471acea91a59b58d2ec5384009e422dcbd (patch)
tree0de5c9168c635fe906f95b99b0d5e8314b232eac /lr.c
parent1ca8ef43eb1f9d5e5904f92045c52b1b91a88f26 (diff)
downloadlr-481cfb471acea91a59b58d2ec5384009e422dcbd.tar.gz
lr-481cfb471acea91a59b58d2ec5384009e422dcbd.tar.xz
lr-481cfb471acea91a59b58d2ec5384009e422dcbd.zip
add relative and parsed date comparisons
Diffstat (limited to 'lr.c')
-rw-r--r--lr.c120
1 files changed, 111 insertions, 9 deletions
diff --git a/lr.c b/lr.c
index 29c59e8..b088b4e 100644
--- a/lr.c
+++ b/lr.c
@@ -378,6 +378,84 @@ parse_string(char **s)
 	return 0;
 }
 
+static int
+parse_dur(int64_t *n)
+{
+	char *s, *r;
+	if (!parse_string(&s))
+		return 0;
+
+	if (*s == '/' || *s == '.') {
+		struct stat st;
+		if (stat(s, &st) < 0)
+			parse_error("can't stat file");
+		*n = st.st_mtime;
+		return 1;
+	}
+
+	struct tm tm = { 0 };
+	r = strptime(s, "%Y-%m-%d %H:%M:%S", &tm);
+	if (r && !*r) {
+		*n = mktime(&tm);
+		return 1;
+	}
+	r = strptime(s, "%Y-%m-%d", &tm);
+	if (r && !*r) {
+		tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+		*n = mktime(&tm);
+		return 1;
+	}
+	r = strptime(s, "%H:%M:%S", &tm);
+	if (r && !*r) {
+		struct tm *tmnow = localtime(&now);
+		tm.tm_year = tmnow->tm_year;
+		tm.tm_mon = tmnow->tm_mon;
+		tm.tm_mday = tmnow->tm_mday;
+		*n = mktime(&tm);
+		return 1;
+	}
+	r = strptime(s, "%H:%M", &tm);
+	if (r && !*r) {
+		struct tm *tmnow = localtime(&now);
+		tm.tm_year = tmnow->tm_year;
+		tm.tm_mon = tmnow->tm_mon;
+		tm.tm_mday = tmnow->tm_mday;
+		tm.tm_sec = 0;
+		*n = mktime(&tm);
+		return 1;
+	}
+
+	if (*s == '-') {
+		s++;
+
+		errno = 0;
+		int64_t d;
+		d = strtol(s, &r, 10);
+		if (errno == 0 && r[0] == 'd' && !r[1]) {
+			struct tm *tmnow = localtime(&now);
+			tmnow->tm_mday -= d;
+			tmnow->tm_hour = tmnow->tm_min = tmnow->tm_sec = 0;
+			*n = mktime(tmnow);
+			return 1;
+		}
+		if (errno == 0 && r[0] == 'h' && !r[1]) {
+			*n = now - (d*60*60);
+			return 1;
+		}
+		if (errno == 0 && r[0] == 'm' && !r[1]) {
+			*n = now - (d*60);
+			return 1;
+		}
+		if (errno == 0 && r[0] == 's' && !r[1]) {
+			*n = now - d;
+			return 1;
+		}
+	}
+
+	parse_error("invalid time format");
+	return 0;
+}
+
 static struct expr *
 parse_strcmp()
 {
@@ -477,11 +555,7 @@ parse_cmp()
 	enum prop prop;
 	enum op op;
 
-	if (token("atime"))
-		prop = PROP_ATIME;
-	else if (token("ctime"))
-		prop = PROP_CTIME;
-	else if (token("depth"))
+	if (token("depth"))
 		prop = PROP_DEPTH;
 	else if (token("dev"))
 		prop = PROP_DEV;
@@ -495,8 +569,6 @@ parse_cmp()
 		prop = PROP_LINKS;
 	else if (token("mode"))
 		return parse_mode();
-	else if (token("mtime"))
-		prop = PROP_MTIME;
 	else if (token("rdev"))
 		prop = PROP_RDEV;
 	else if (token("size"))
@@ -524,6 +596,36 @@ parse_cmp()
 }
 
 static struct expr *
+parse_timecmp()
+{
+	enum prop prop;
+	enum op op;
+
+	if (token("atime"))
+		prop = PROP_ATIME;
+	else if (token("ctime"))
+		prop = PROP_CTIME;
+	else if (token("mtime"))
+		prop = PROP_MTIME;
+	else
+		return parse_cmp();
+
+	op = parse_op();
+	if (!op)
+		parse_error("invalid comparison");
+
+	int64_t n;
+	if (parse_num(&n) || parse_dur(&n)) {
+		struct expr *e = mkexpr(op);
+		e->a.prop = prop;
+		e->b.num = n;
+		return e;
+	}
+
+	return 0;
+}
+
+static struct expr *
 chain(struct expr *e1, enum op op, struct expr *e2)
 {
 	struct expr *i, *j, *e;
@@ -548,11 +650,11 @@ chain(struct expr *e1, enum op op, struct expr *e2)
 static struct expr *
 parse_and()
 {
-	struct expr *e1 = parse_cmp();
+	struct expr *e1 = parse_timecmp();
 	struct expr *r = e1;
 
 	while (token("&&")) {
-		struct expr *e2 = parse_cmp();
+		struct expr *e2 = parse_timecmp();
 		r = chain(r, EXPR_AND, e2);
 	}