Both are pure string functions now, but nothing exercised them below the
integration tests, which only drive the binary. real_name took a whole Passwd
to read two of its fields, and Passwd has no Default and platform-dependent
members, so hand it the login and the comment field instead; that also drops a
clone. The cases worth pinning are the boundaries: blanks under a minute,
hours past it, days past a day, the comma that ends the real name, and & in
the comment field standing in for the login.
The row builders format into a String, which cannot fail, so every write ended
in a discarded Result. Put that behind a column! helper that says so once and
names what the line is doing. Capitalize was a public trait on str with a
single caller inside the crate; a plain function does the same in four lines.
Note while passing that -s is parsed only to be ignored.
format_timestamp read the locale out of the environment and parsed a format
description on every line it rendered, though neither can change while the
listing is being printed. Keep the chosen description in a thread local beside
NOW, which already caches the clock for the same reason.
The row and header printers walked the columns writing straight to stdout.
Have them return the finished line instead, so the listing does the writing
and the padding rules for a row live in one place. The long report gets the
same treatment: an early continue for an account with no password entry,
and the home directory read once. Rename the helpers that are left along
the way -- idle_string, time_string and gecos_to_fullname become
format_idle, format_timestamp and real_name -- and drop the stale
spell-checker list, whose words no longer appear.
Whether a session's terminal takes messages and when it was last read from
both come out of one stat, so let a Terminal value carry the pair and keep
the "unknown" case in one place: an unreadable device and a zero atime are
the same thing to the caller, which is what Option says. This drops the
deferred-assignment dance in the row builder.
Sort the eight loose booleans by what they actually decide: Layout holds
the columns of the short listing, Details holds how much of an account the
long report spells out, and the host lookup stays on Pinky itself. The
three narrowing flags now read as one stacked expression instead of a
chain of assignments.
- Add conditional compilation for WASI target to avoid panics from `std::env::temp_dir()`
- Implement fallback logic in `Options` to read TMPDIR environment variable directly on WASI
- Update `get_tmpdir_env_or_default()` with WASI-specific handling for temp directory resolution
- Add `#[cfg_attr]` annotations to skip host path-dependent tests on WASI sandbox environment
- Ignore 14 tests that require host filesystem access when running under wasi_runner
- Ignore directory permission test on WASI due to lack of `chmod` support and mode parameter limitations
Replace unsafe Win32 calls and raw bitmasks with safe Rust standard library
APIs across Windows implementations:
- mv: use OpenOptionsExt access_mode for delete check
- sync: use File::sync_all instead of FlushFileBuffers
- hostname: remove redundant manual Winsock initialization
- touch: use io::Error::last_os_error instead of GetLastError
- rm: use Metadata::permissions().readonly() and FileTypeExt::is_symlink_dir()