diff options
-rw-r--r-- | README.md | 19 | ||||
-rw-r--r-- | lr.c | 120 |
2 files changed, 128 insertions, 11 deletions
diff --git a/README.md b/README.md index fd6d051..afa9c17 100644 --- a/README.md +++ b/README.md @@ -121,17 +121,32 @@ Default: `n`. | <expr> && <expr> -- conjunction | ! <expr> -- negation | ( <expr ) + | <timeprop> <numop> <dur> | <numprop> <numop> <num> | <strprop> <strop> <str> | <typetest> | <modetest> | prune -- do not traverse into subdirectories | print -- always true value + + <timeprop> ::= atime | ctime | mtime - <numprop> ::= atime | ctime | depth | dev | entries | gid | inode - | links | mode | mtime | rdev | size | total | uid + <numprop> ::= depth | dev | entries | gid | inode + | links | mode | rdev | size | total | uid <numop> ::= <= | < | >= | > | == | != + + <dur> ::= "./path" -- mtime of relative path + | "/path" -- mtime of absolute path + | "YYYY-MM-DD HH:MM:SS" + | "YYYY-MM-DD" -- at midnight + | "HH:MM:SS" -- today + | "HH:MM" -- today + | "-[0-9]+d" -- n days ago at midnight + | "-[0-9]+h" -- n hours before now + | "-[0-9]+m" -- n minutes before now + | "-[0-9]+s" -- n seconds before now + | [0-9]+ -- absolute epoch time <num> ::= [0-9]+ ( c -- *1 | b -- *512 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); } |