mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-22 21:51:54 +08:00
builtin test: Implement -ot, -nt, -ef
These are non-POSIX extensions other test(1) utilities implement, which compares the modification time of two files as proposed for fish in #3589: testing if one file is newer than another file. -ef is a common extension to test(1) which checks if two paths refer to the same file, by comparing the dev and inode numbers.
This commit is contained in:
parent
7bdc712615
commit
8f91ee7f6b
@ -65,6 +65,10 @@ enum token_t {
|
|||||||
test_string_equal, // "=", true if strings are identical
|
test_string_equal, // "=", true if strings are identical
|
||||||
test_string_not_equal, // "!=", true if strings are not identical
|
test_string_not_equal, // "!=", true if strings are not identical
|
||||||
|
|
||||||
|
test_file_newer, // f1 -nt f2, true if f1 exists and is newer than f2, or there is no f2
|
||||||
|
test_file_older, // f1 -ot f2, true if f2 exists and f1 does not, or f1 is older than f2
|
||||||
|
test_file_same, // f1 -ef f2, true if f1 and f2 exist and refer to same file
|
||||||
|
|
||||||
test_number_equal, // "-eq", true if numbers are equal
|
test_number_equal, // "-eq", true if numbers are equal
|
||||||
test_number_not_equal, // "-ne", true if numbers are not equal
|
test_number_not_equal, // "-ne", true if numbers are not equal
|
||||||
test_number_greater, // "-gt", true if first number is larger than second
|
test_number_greater, // "-gt", true if first number is larger than second
|
||||||
@ -152,6 +156,9 @@ static const token_info_t *token_for_string(const wcstring &str) {
|
|||||||
{L"-z", {test_string_z, UNARY_PRIMARY}},
|
{L"-z", {test_string_z, UNARY_PRIMARY}},
|
||||||
{L"=", {test_string_equal, BINARY_PRIMARY}},
|
{L"=", {test_string_equal, BINARY_PRIMARY}},
|
||||||
{L"!=", {test_string_not_equal, BINARY_PRIMARY}},
|
{L"!=", {test_string_not_equal, BINARY_PRIMARY}},
|
||||||
|
{L"-nt", {test_file_newer, BINARY_PRIMARY}},
|
||||||
|
{L"-ot", {test_file_older, BINARY_PRIMARY}},
|
||||||
|
{L"-ef", {test_file_same, BINARY_PRIMARY}},
|
||||||
{L"-eq", {test_number_equal, BINARY_PRIMARY}},
|
{L"-eq", {test_number_equal, BINARY_PRIMARY}},
|
||||||
{L"-ne", {test_number_not_equal, BINARY_PRIMARY}},
|
{L"-ne", {test_number_not_equal, BINARY_PRIMARY}},
|
||||||
{L"-gt", {test_number_greater, BINARY_PRIMARY}},
|
{L"-gt", {test_number_greater, BINARY_PRIMARY}},
|
||||||
@ -742,6 +749,15 @@ static bool binary_primary_evaluate(test_expressions::token_t token, const wcstr
|
|||||||
case test_string_not_equal: {
|
case test_string_not_equal: {
|
||||||
return left != right;
|
return left != right;
|
||||||
}
|
}
|
||||||
|
case test_file_newer: {
|
||||||
|
return file_id_for_path(right).older_than(file_id_for_path(left));
|
||||||
|
}
|
||||||
|
case test_file_older: {
|
||||||
|
return file_id_for_path(left).older_than(file_id_for_path(right));
|
||||||
|
}
|
||||||
|
case test_file_same: {
|
||||||
|
return file_id_for_path(left) == file_id_for_path(right);
|
||||||
|
}
|
||||||
case test_number_equal: {
|
case test_number_equal: {
|
||||||
return parse_number(left, &ln, errors) && parse_number(right, &rn, errors) &&
|
return parse_number(left, &ln, errors) && parse_number(right, &rn, errors) &&
|
||||||
ln.compare(rn) == 0;
|
ln.compare(rn) == 0;
|
||||||
|
@ -868,6 +868,22 @@ static int compare(T a, T b) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \return true if \param rhs has higher mtime seconds than this file_id_t.
|
||||||
|
/// If identical, nanoseconds are compared.
|
||||||
|
bool file_id_t::older_than(const file_id_t &rhs) const {
|
||||||
|
int ret = compare(mod_seconds, rhs.mod_seconds);
|
||||||
|
if (!ret) ret = compare(mod_nanoseconds, rhs.mod_nanoseconds);
|
||||||
|
switch (ret) {
|
||||||
|
case -1:
|
||||||
|
return true;
|
||||||
|
case 1:
|
||||||
|
case 0:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
DIE("unreachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int file_id_t::compare_file_id(const file_id_t &rhs) const {
|
int file_id_t::compare_file_id(const file_id_t &rhs) const {
|
||||||
// Compare each field, stopping when we get to a non-equal field.
|
// Compare each field, stopping when we get to a non-equal field.
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
11
src/wutil.h
11
src/wutil.h
@ -145,9 +145,14 @@ struct file_id_t {
|
|||||||
dev_t device{static_cast<dev_t>(-1LL)};
|
dev_t device{static_cast<dev_t>(-1LL)};
|
||||||
ino_t inode{static_cast<ino_t>(-1LL)};
|
ino_t inode{static_cast<ino_t>(-1LL)};
|
||||||
uint64_t size{static_cast<uint64_t>(-1LL)};
|
uint64_t size{static_cast<uint64_t>(-1LL)};
|
||||||
time_t change_seconds{-1};
|
/* some platforms handle negative time_t
|
||||||
|
values to represent WW1-era dates, initialize ancient
|
||||||
|
for the sake of comparisons.
|
||||||
|
tv_nsec's meaningful values are REALLY [0, 999999999]
|
||||||
|
this nanosecond component we'll initialize at 0. */
|
||||||
|
time_t change_seconds{std::numeric_limits<time_t>::min()};
|
||||||
long change_nanoseconds{-1};
|
long change_nanoseconds{-1};
|
||||||
time_t mod_seconds{-1};
|
time_t mod_seconds{std::numeric_limits<time_t>::min()};
|
||||||
long mod_nanoseconds{-1};
|
long mod_nanoseconds{-1};
|
||||||
|
|
||||||
constexpr file_id_t() = default;
|
constexpr file_id_t() = default;
|
||||||
@ -159,7 +164,7 @@ struct file_id_t {
|
|||||||
bool operator<(const file_id_t &rhs) const;
|
bool operator<(const file_id_t &rhs) const;
|
||||||
|
|
||||||
static file_id_t from_stat(const struct stat &buf);
|
static file_id_t from_stat(const struct stat &buf);
|
||||||
|
bool older_than(const file_id_t &rhs) const;
|
||||||
wcstring dump() const;
|
wcstring dump() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user