summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c8
-rw-r--r--expr.h2
-rw-r--r--parse.c95
-rwxr-xr-xtests.sh6
-rw-r--r--tests/test_mtime_units.out5
5 files changed, 102 insertions, 14 deletions
diff --git a/eval.c b/eval.c
index c638f10..3a5ab12 100644
--- a/eval.c
+++ b/eval.c
@@ -236,11 +236,13 @@ bool eval_time(const struct expr *expr, struct eval_state *state) {
time_t diff = timespec_diff(&expr->reftime, time);
switch (expr->time_unit) {
+ case DAYS:
+ diff /= 60*24;
+ fallthrough;
case MINUTES:
diff /= 60;
- break;
- case DAYS:
- diff /= 60*60*24;
+ fallthrough;
+ case SECONDS:
break;
}
diff --git a/expr.h b/expr.h
index 562d84e..c8c8ce0 100644
--- a/expr.h
+++ b/expr.h
@@ -65,6 +65,8 @@ enum mode_cmp {
* Possible time units.
*/
enum time_unit {
+ /** Seconds. */
+ SECONDS,
/** Minutes. */
MINUTES,
/** Days. */
diff --git a/parse.c b/parse.c
index 6ad580b..5983430 100644
--- a/parse.c
+++ b/parse.c
@@ -916,9 +916,9 @@ fail:
}
/**
- * Parse -[aBcm]{min,time}.
+ * Parse -[aBcm]min.
*/
-static struct expr *parse_time(struct parser_state *state, int field, int unit) {
+static struct expr *parse_min(struct parser_state *state, int field, int arg2) {
struct expr *expr = parse_test_icmp(state, eval_time);
if (!expr) {
return NULL;
@@ -927,11 +927,84 @@ static struct expr *parse_time(struct parser_state *state, int field, int unit)
expr->cost = STAT_COST;
expr->reftime = state->now;
expr->stat_field = field;
- expr->time_unit = unit;
+ expr->time_unit = MINUTES;
return expr;
}
/**
+ * Parse -[aBcm]time.
+ */
+static struct expr *parse_time(struct parser_state *state, int field, int arg2) {
+ struct expr *expr = parse_unary_test(state, eval_time);
+ if (!expr) {
+ return NULL;
+ }
+
+ expr->cost = STAT_COST;
+ expr->reftime = state->now;
+ expr->stat_field = field;
+
+ const char *tail = parse_icmp(state, expr->sdata, expr, IF_PARTIAL_OK);
+ if (!tail) {
+ goto fail;
+ }
+
+ if (!*tail) {
+ expr->time_unit = DAYS;
+ return expr;
+ }
+
+ unsigned long long time = expr->idata;
+ expr->idata = 0;
+
+ while (true) {
+ switch (*tail) {
+ case 'w':
+ time *= 7;
+ fallthrough;
+ case 'd':
+ time *= 24;
+ fallthrough;
+ case 'h':
+ time *= 60;
+ fallthrough;
+ case 'm':
+ time *= 60;
+ fallthrough;
+ case 's':
+ break;
+ default:
+ parse_error(state, "${blu}%s${rs} ${bld}%s${rs}: Unknown time unit ${bld}%c${rs}.\n",
+ expr->argv[0], expr->argv[1], *tail);
+ goto fail;
+ }
+
+ expr->idata += time;
+
+ if (!*++tail) {
+ break;
+ }
+
+ tail = parse_int(state, tail, &time, IF_PARTIAL_OK | IF_LONG_LONG | IF_UNSIGNED);
+ if (!tail) {
+ goto fail;
+ }
+ if (!*tail) {
+ parse_error(state, "${blu}%s${rs} ${bld}%s${rs}: Missing time unit.\n",
+ expr->argv[0], expr->argv[1]);
+ goto fail;
+ }
+ }
+
+ expr->time_unit = SECONDS;
+ return expr;
+
+fail:
+ free_expr(expr);
+ return NULL;
+}
+
+/**
* Parse -capable.
*/
static struct expr *parse_capable(struct parser_state *state, int flag, int arg2) {
@@ -2893,10 +2966,10 @@ static const struct table_entry parse_table[] = {
{"--", T_FLAG},
{"--help", T_ACTION, parse_help},
{"--version", T_ACTION, parse_version},
- {"-Bmin", T_TEST, parse_time, BFS_STAT_BTIME, MINUTES},
+ {"-Bmin", T_TEST, parse_min, BFS_STAT_BTIME},
{"-Bnewer", T_TEST, parse_newer, BFS_STAT_BTIME},
{"-Bsince", T_TEST, parse_since, BFS_STAT_BTIME},
- {"-Btime", T_TEST, parse_time, BFS_STAT_BTIME, DAYS},
+ {"-Btime", T_TEST, parse_time, BFS_STAT_BTIME},
{"-D", T_FLAG, parse_debug},
{"-E", T_FLAG, parse_regex_extended},
{"-H", T_FLAG, parse_follow, BFTW_FOLLOW_ROOTS, false},
@@ -2907,17 +2980,17 @@ static const struct table_entry parse_table[] = {
{"-X", T_FLAG, parse_xargs_safe},
{"-a", T_OPERATOR},
{"-acl", T_TEST, parse_acl},
- {"-amin", T_TEST, parse_time, BFS_STAT_ATIME, MINUTES},
+ {"-amin", T_TEST, parse_min, BFS_STAT_ATIME},
{"-and", T_OPERATOR},
{"-anewer", T_TEST, parse_newer, BFS_STAT_ATIME},
{"-asince", T_TEST, parse_since, BFS_STAT_ATIME},
- {"-atime", T_TEST, parse_time, BFS_STAT_ATIME, DAYS},
+ {"-atime", T_TEST, parse_time, BFS_STAT_ATIME},
{"-capable", T_TEST, parse_capable},
- {"-cmin", T_TEST, parse_time, BFS_STAT_CTIME, MINUTES},
+ {"-cmin", T_TEST, parse_min, BFS_STAT_CTIME},
{"-cnewer", T_TEST, parse_newer, BFS_STAT_CTIME},
{"-color", T_OPTION, parse_color, true},
{"-csince", T_TEST, parse_since, BFS_STAT_CTIME},
- {"-ctime", T_TEST, parse_time, BFS_STAT_CTIME, DAYS},
+ {"-ctime", T_TEST, parse_time, BFS_STAT_CTIME},
{"-d", T_FLAG, parse_depth},
{"-daystart", T_OPTION, parse_daystart},
{"-delete", T_ACTION, parse_delete},
@@ -2953,11 +3026,11 @@ static const struct table_entry parse_table[] = {
{"-ls", T_ACTION, parse_ls},
{"-maxdepth", T_OPTION, parse_depth_limit, false},
{"-mindepth", T_OPTION, parse_depth_limit, true},
- {"-mmin", T_TEST, parse_time, BFS_STAT_MTIME, MINUTES},
+ {"-mmin", T_TEST, parse_min, BFS_STAT_MTIME},
{"-mnewer", T_TEST, parse_newer, BFS_STAT_MTIME},
{"-mount", T_OPTION, parse_mount},
{"-msince", T_TEST, parse_since, BFS_STAT_MTIME},
- {"-mtime", T_TEST, parse_time, BFS_STAT_MTIME, DAYS},
+ {"-mtime", T_TEST, parse_time, BFS_STAT_MTIME},
{"-name", T_TEST, parse_name, false},
{"-newer", T_TEST, parse_newer, BFS_STAT_MTIME},
{"-newer", T_TEST, parse_newerxy, 0, 0, true},
diff --git a/tests.sh b/tests.sh
index e58993f..5aa5a8d 100755
--- a/tests.sh
+++ b/tests.sh
@@ -389,6 +389,8 @@ bsd_tests=(
test_msince
+ test_mtime_units
+
test_name_slash
test_name_slashes
@@ -2019,6 +2021,10 @@ function test_msince() {
bfs_diff times -msince 1991-12-14T00:01
}
+function test_mtime_units() {
+ bfs_diff times -mtime +500w400d300h200m100s
+}
+
function test_size_T() {
bfs_diff basic -type f -size 1T
}
diff --git a/tests/test_mtime_units.out b/tests/test_mtime_units.out
new file mode 100644
index 0000000..f7f63b0
--- /dev/null
+++ b/tests/test_mtime_units.out
@@ -0,0 +1,5 @@
+times
+times/a
+times/b
+times/c
+times/l