mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-08-06 07:57:48 +00:00
ls: implement -c and -u
This commit is contained in:
parent
c454d2640c
commit
c86c18cbb5
1 changed files with 63 additions and 27 deletions
|
@ -54,7 +54,6 @@ extern crate uucore;
|
|||
|
||||
use clap::{App, Arg};
|
||||
use number_prefix::NumberPrefix;
|
||||
use std::cmp::Reverse;
|
||||
#[cfg(unix)]
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
|
@ -66,6 +65,10 @@ use std::os::unix::fs::MetadataExt;
|
|||
#[cfg(windows)]
|
||||
use std::os::windows::fs::MetadataExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::cmp::Reverse;
|
||||
#[cfg(not(unix))]
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
|
||||
use time::{strftime, Timespec};
|
||||
#[cfg(unix)]
|
||||
|
@ -121,7 +124,10 @@ pub mod options {
|
|||
pub static SIZE: &str = "S";
|
||||
pub static TIME: &str = "t";
|
||||
pub static NONE: &str = "U";
|
||||
pub static CTIME: &str = "c";
|
||||
}
|
||||
pub mod time {
|
||||
pub static ACCESS: &str = "u";
|
||||
pub static CHANGE: &str = "c";
|
||||
}
|
||||
pub static IGNORE_BACKUPS: &str = "ignore-backups";
|
||||
pub static DIRECTORY: &str = "directory";
|
||||
|
@ -148,7 +154,6 @@ enum Sort {
|
|||
Name,
|
||||
Size,
|
||||
Time,
|
||||
CTime,
|
||||
}
|
||||
|
||||
enum SizeFormats {
|
||||
|
@ -163,6 +168,12 @@ enum Files {
|
|||
Normal,
|
||||
}
|
||||
|
||||
enum Time {
|
||||
Modification,
|
||||
Access,
|
||||
Change,
|
||||
}
|
||||
|
||||
struct Config {
|
||||
display: DisplayOptions,
|
||||
files: Files,
|
||||
|
@ -175,6 +186,7 @@ struct Config {
|
|||
size_format: SizeFormats,
|
||||
numeric_uid_gid: bool,
|
||||
directory: bool,
|
||||
time: Time,
|
||||
#[cfg(unix)]
|
||||
inode: bool,
|
||||
#[cfg(unix)]
|
||||
|
@ -201,8 +213,6 @@ impl Config {
|
|||
|
||||
let sort = if options.is_present(options::sort::TIME) {
|
||||
Sort::Time
|
||||
} else if options.is_present(options::sort::CTIME) {
|
||||
Sort::CTime
|
||||
} else if options.is_present(options::sort::SIZE) {
|
||||
Sort::Size
|
||||
} else if options.is_present(options::sort::NONE) {
|
||||
|
@ -211,6 +221,14 @@ impl Config {
|
|||
Sort::Name
|
||||
};
|
||||
|
||||
let time = if options.is_present(options::time::ACCESS) {
|
||||
Time::Access
|
||||
} else if options.is_present(options::time::CHANGE) {
|
||||
Time::Change
|
||||
} else {
|
||||
Time::Modification
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
let color = if options.is_present(options::COLOR) {
|
||||
match options.value_of(options::COLOR) {
|
||||
|
@ -243,6 +261,7 @@ impl Config {
|
|||
size_format,
|
||||
numeric_uid_gid: options.is_present(options::NUMERIC_UID_GID),
|
||||
directory: options.is_present(options::DIRECTORY),
|
||||
time,
|
||||
#[cfg(unix)]
|
||||
color,
|
||||
#[cfg(unix)]
|
||||
|
@ -287,13 +306,21 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.help("Ignore entries which end with ~."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::sort::CTIME)
|
||||
.short(options::sort::CTIME)
|
||||
.help("If the long listing format (e.g., -l, -o) is being used, print the status \
|
||||
Arg::with_name(options::time::CHANGE)
|
||||
.short(options::time::CHANGE)
|
||||
.help("If the long listing format (e.g., -l, -o) is being used, print the status \
|
||||
change time (the ‘ctime’ in the inode) instead of the modification time. When \
|
||||
explicitly sorting by time (--sort=time or -t) or when not using a long listing \
|
||||
format, sort according to the status change time.",
|
||||
))
|
||||
.arg(
|
||||
Arg::with_name(options::time::ACCESS)
|
||||
.short(options::time::ACCESS)
|
||||
.help("If the long listing format (e.g., -l, -o) is being used, print the status \
|
||||
access time instead of the modification time. When explicitly sorting by time \
|
||||
(--sort=time or -t) or when not using a long listing format, sort according to the \
|
||||
status change time.")
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::DIRECTORY)
|
||||
.short("d")
|
||||
|
@ -449,13 +476,11 @@ fn list(locs: Vec<String>, config: Config) -> i32 {
|
|||
#[cfg(any(unix, target_os = "redox"))]
|
||||
fn sort_entries(entries: &mut Vec<PathBuf>, config: &Config) {
|
||||
match config.sort {
|
||||
Sort::CTime => entries
|
||||
.sort_by_key(|k| Reverse(get_metadata(k, config).map(|md| md.ctime()).unwrap_or(0))),
|
||||
Sort::Time => entries.sort_by_key(|k| {
|
||||
Reverse(
|
||||
get_metadata(k, config)
|
||||
.and_then(|md| md.modified())
|
||||
.unwrap_or(std::time::UNIX_EPOCH),
|
||||
.map(|md| get_time(&md, config))
|
||||
.unwrap_or(0),
|
||||
)
|
||||
}),
|
||||
Sort::Size => entries
|
||||
|
@ -484,13 +509,9 @@ fn is_hidden(file_path: &DirEntry) -> bool {
|
|||
#[cfg(windows)]
|
||||
fn sort_entries(entries: &mut Vec<PathBuf>, config: &Config) {
|
||||
match config.sort {
|
||||
Sort::CTime | Sort::Time => entries.sort_by_key(|k| {
|
||||
Sort::Time => entries.sort_by_key(|k| {
|
||||
// Newest first
|
||||
Reverse(
|
||||
get_metadata(k, config)
|
||||
.and_then(|md| md.modified())
|
||||
.unwrap_or(std::time::UNIX_EPOCH),
|
||||
)
|
||||
Reverse(get_time(get_metadata(k, config), config).unwrap_or(std::time::UNIX_EPOCH))
|
||||
}),
|
||||
Sort::Size => entries.sort_by_key(|k| {
|
||||
// Largest first
|
||||
|
@ -702,23 +723,38 @@ fn display_group(_metadata: &Metadata, _config: &Config) -> String {
|
|||
"somegroup".to_string()
|
||||
}
|
||||
|
||||
// The implementations for get_time are separated because some options, such
|
||||
// as ctime will not be available
|
||||
#[cfg(unix)]
|
||||
fn get_time(md: &Metadata, config: &Config) -> i64 {
|
||||
match config.time {
|
||||
Time::Change => md.ctime(),
|
||||
Time::Modification => md.mtime(),
|
||||
Time::Access => md.atime(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn get_time(md: &Metadata, config: &Config) -> Option<SystemTime> {
|
||||
match config.time {
|
||||
Time::Modification => md.modification().ok(),
|
||||
Time::Access => md.access().ok(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn display_date(metadata: &Metadata, config: &Config) -> String {
|
||||
let secs = match config.sort {
|
||||
Sort::CTime => metadata.ctime(),
|
||||
Sort::Time => metadata.mtime(),
|
||||
_ => 0,
|
||||
};
|
||||
let secs = get_time(metadata, config);
|
||||
let time = time::at(Timespec::new(secs, 0));
|
||||
strftime("%F %R", &time).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn display_date(metadata: &Metadata, _config: &Config) -> String {
|
||||
if let Ok(mtime) = metadata.modified() {
|
||||
fn display_date(metadata: &Metadata, config: &Config) -> String {
|
||||
if let Some(time) = get_time(metadata, config) {
|
||||
let time = time::at(Timespec::new(
|
||||
mtime
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
time.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs() as i64,
|
||||
0,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue