From 50d96ddf757dde6cbfcdd4b248ff559daa2fd72c Mon Sep 17 00:00:00 2001 From: sebihutanu1 Date: Sun, 21 Jan 2024 22:19:06 +0200 Subject: [PATCH 1/7] tema-opensource --- .github/ISSUE_TEMPLATE/bug_report.md | 76 +- .github/ISSUE_TEMPLATE/custom.md | 20 +- .github/ISSUE_TEMPLATE/feature_request.md | 40 +- .github/PULL_REQUEST_TEMPLATE.md | 6 +- .github/dependabot.yml | 16 +- .github/workflows/ci.yml | 422 +++---- .gitignore | 12 +- .rustfmt.toml | 18 +- CHANGELOG.md | 544 ++++---- CODE_OF_CONDUCT.md | 152 +-- CONTRIBUTING.md | 44 +- Cargo.toml | 85 +- LICENSE_APACHE | 352 +++--- LICENSE_BOOST | 46 +- LICENSE_MIT | 38 +- README.md | 186 +-- WASM.md | 96 +- examples/os-strings.rs | 84 +- examples/web/Cargo.toml | 72 +- examples/web/README.md | 30 +- examples/web/index.html | 28 +- examples/web/rust-toolchain | 4 +- examples/web/src/lib.rs | 114 +- examples/whoami-demo.rs | 84 +- res/icon.svg | 216 ++-- rust-toolchain | 4 +- src/disp.rs | 250 ++++ src/fake.rs | 150 +-- src/fallible.rs | 194 +-- src/lib.rs | 1199 +++++++++--------- src/unix.rs | 1362 ++++++++++----------- src/web.rs | 494 ++++---- src/windows.rs | 968 +++++++-------- 33 files changed, 3830 insertions(+), 3576 deletions(-) create mode 100644 src/disp.rs diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7..6867cf8 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,38 +1,38 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md index 48d5f81..3e9dad0 100644 --- a/.github/ISSUE_TEMPLATE/custom.md +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -1,10 +1,10 @@ ---- -name: Custom issue template -about: Describe this issue template's purpose here. -title: '' -labels: '' -assignees: '' - ---- - - +--- +name: Custom issue template +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..72718d5 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,20 +1,20 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 532d019..8a09558 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,3 @@ - - - + + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 13b2d4f..479c265 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,8 @@ -version: 2 -updates: -- package-ecosystem: cargo - directory: "/" - schedule: - interval: daily - time: "10:00" - open-pull-requests-limit: 10 +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + time: "10:00" + open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f5f91a..a461253 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,211 +1,211 @@ -on: [push, pull_request] - -name: tests - -jobs: - checks: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - tc: [nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - components: rustfmt, clippy - override: true - - run: cargo fmt --check - - run: cargo clippy -- -D warnings - checks-cross-compile: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [nightly] - cc: - - aarch64-linux-android - - i686-pc-windows-gnu - - i686-unknown-freebsd - - i686-unknown-linux-gnu - - wasm32-wasi - - x86_64-apple-darwin - - x86_64-unknown-redox - - x86_64-unknown-illumos - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - checks-cross-compile-ios: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [nightly] - cc: [aarch64-apple-ios] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - checks-cross-compile-wasm: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [nightly] - cc: [wasm32-unknown-unknown] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo update -p bumpalo --precise 3.4.0 - - run: cargo update -p web-sys --precise 0.3.55 - - run: cargo update -p js-sys --precise 0.3.55 - - run: cargo update -p wasm-bindgen --precise 0.2.78 - - run: cargo update -p log --precise 0.4.17 - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - - run: cargo clippy --no-default-features --target=${{ matrix.cc }} -- -D warnings - - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo clippy --target=${{ matrix.cc }} -- -D warnings - test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest] - tc: [1.40.0, stable, beta, nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - override: true - - run: cargo test --all --all-features - test-macos: - runs-on: macos-latest - strategy: - matrix: - tc: [stable, beta, nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - override: true - - run: cargo test --all --all-features --target=x86_64-apple-darwin - cross-compile: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.40.0, stable, beta, nightly] - cc: - - aarch64-linux-android - - i686-pc-windows-gnu - - i686-unknown-freebsd - - i686-unknown-linux-gnu - - wasm32-wasi - - x86_64-apple-darwin - - x86_64-unknown-redox - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-ios: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [1.40.0, stable, beta, nightly] - cc: [aarch64-apple-ios] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-m1: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [stable, beta, nightly] - cc: [aarch64-apple-darwin] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-wasm: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.40.0, stable, beta, nightly] - cc: [wasm32-unknown-unknown] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo update -p bumpalo --precise 3.4.0 - - run: cargo update -p web-sys --precise 0.3.55 - - run: cargo update -p js-sys --precise 0.3.55 - - run: cargo update -p wasm-bindgen --precise 0.2.78 - - run: cargo update -p log --precise 0.4.17 - - run: cargo update -p quote --precise 1.0.30 - - run: cargo update -p proc-macro2 --precise 1.0.63 - - run: cargo build --all-features --target=${{ matrix.cc }} - - run: cargo build --no-default-features --target=${{ matrix.cc }} - - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo build --target=${{ matrix.cc }} - cross-compile-illumos: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.65.0, stable, beta, nightly] - cc: - - x86_64-unknown-illumos - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} +on: [push, pull_request] + +name: tests + +jobs: + checks: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + tc: [nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + components: rustfmt, clippy + override: true + - run: cargo fmt --check + - run: cargo clippy -- -D warnings + checks-cross-compile: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [nightly] + cc: + - aarch64-linux-android + - i686-pc-windows-gnu + - i686-unknown-freebsd + - i686-unknown-linux-gnu + - wasm32-wasi + - x86_64-apple-darwin + - x86_64-unknown-redox + - x86_64-unknown-illumos + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + checks-cross-compile-ios: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [nightly] + cc: [aarch64-apple-ios] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + checks-cross-compile-wasm: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [nightly] + cc: [wasm32-unknown-unknown] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo update -p bumpalo --precise 3.4.0 + - run: cargo update -p web-sys --precise 0.3.55 + - run: cargo update -p js-sys --precise 0.3.55 + - run: cargo update -p wasm-bindgen --precise 0.2.78 + - run: cargo update -p log --precise 0.4.17 + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + - run: cargo clippy --no-default-features --target=${{ matrix.cc }} -- -D warnings + - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo clippy --target=${{ matrix.cc }} -- -D warnings + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + tc: [1.40.0, stable, beta, nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + override: true + - run: cargo test --all --all-features + test-macos: + runs-on: macos-latest + strategy: + matrix: + tc: [stable, beta, nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + override: true + - run: cargo test --all --all-features --target=x86_64-apple-darwin + cross-compile: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.40.0, stable, beta, nightly] + cc: + - aarch64-linux-android + - i686-pc-windows-gnu + - i686-unknown-freebsd + - i686-unknown-linux-gnu + - wasm32-wasi + - x86_64-apple-darwin + - x86_64-unknown-redox + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-ios: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [1.40.0, stable, beta, nightly] + cc: [aarch64-apple-ios] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-m1: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [stable, beta, nightly] + cc: [aarch64-apple-darwin] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-wasm: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.40.0, stable, beta, nightly] + cc: [wasm32-unknown-unknown] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo update -p bumpalo --precise 3.4.0 + - run: cargo update -p web-sys --precise 0.3.55 + - run: cargo update -p js-sys --precise 0.3.55 + - run: cargo update -p wasm-bindgen --precise 0.2.78 + - run: cargo update -p log --precise 0.4.17 + - run: cargo update -p quote --precise 1.0.30 + - run: cargo update -p proc-macro2 --precise 1.0.63 + - run: cargo build --all-features --target=${{ matrix.cc }} + - run: cargo build --no-default-features --target=${{ matrix.cc }} + - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo build --target=${{ matrix.cc }} + cross-compile-illumos: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.65.0, stable, beta, nightly] + cc: + - x86_64-unknown-illumos + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} diff --git a/.gitignore b/.gitignore index 7ed80a4..39ca62a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -**/target/ -**/*.rs.bk -Cargo.lock -/ignore/ -/a.out -/**/*.swp +**/target/ +**/*.rs.bk +Cargo.lock +/ignore/ +/a.out +/**/*.swp diff --git a/.rustfmt.toml b/.rustfmt.toml index 5e6866e..48239b7 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,9 +1,9 @@ -# Don't deviate too much, just reduce columns and stricter enforcement -edition = "2021" -unstable_features = true -max_width = 80 -reorder_impl_items = true -group_imports = "StdExternalCrate" -imports_granularity = "Crate" -normalize_doc_attributes = true -wrap_comments = true +# Don't deviate too much, just reduce columns and stricter enforcement +edition = "2021" +unstable_features = true +max_width = 80 +reorder_impl_items = true +group_imports = "StdExternalCrate" +imports_granularity = "Crate" +normalize_doc_attributes = true +wrap_comments = true diff --git a/CHANGELOG.md b/CHANGELOG.md index 04841f3..2a92849 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,272 +1,272 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog], and this project adheres to -[Semantic Versioning]. - -## [1.4.1] - 2023-06-25 -### Fixed - - License files not being included in package on crates.io - -## [1.4.0] - 2023-03-12 -### Added - - Support for Illumos - -## [1.3.0] - 2022-12-28 -### Added - - `Arch` enum listing CPU architectures - - `Width` enum listing CPU architecture address widths - - `arch()` function which returns an `Arch` type representing a CPU - architecture - - `Arch::width()` method which returns the address width of a CPU architecture - - *`web`* feature (enabled by default). Disabling this feature allows you to - use wasm32-unknown-unknown with whoami outside of the browser with a mock - implementation. - - Officially support compiling to WASI or Daku WebAssembly platforms; - functionality not supported yet. - - Convenience `Result` type alias. - -### Changed - - Modernized and cleaned up code style - -### Fixed - - Handling of `lang()` when `$LANG` environment variable on unix set to "C", - causing duplicated iterator elements `["C", "C"]`; now produces `["en-US"]`. - - WhoAmI reporting "Safari" when running in Chrome/Chromium browser - - WhoAmI reporting "Edg" when running in Edge browser (now reports "Edge") - - WhoAmI reporting "OPR" when running in Opera browser (now reports "Opera") - - WhoAmI reporting "Mozilla" when running in GNOME web browser (now reports - "GNOME Web") - -## [1.2.3] - 2022-09-12 -### Fixed - - WebAssembly target requiring older versions of dependencies - -## [1.2.2] - 2022-09-05 -### Added - - More details to the method documentation - -### Changed - - WhoAmI now has an official MSRV of Rust 1.40.0 - - `whoami::hostname()` is now normalized to lowercase - -## [1.2.1] - 2021-11-24 -### Fixed - - The Windows GNU target support being broken - -## [1.2.0] - 2021-11-06 -### Added - - Derives for `Clone`, `PartialEq` and `Eq` on `DesktopEnv` and `Platform` - -### Changed - - Lower MSRV for Windows - -## [1.1.5] - 2021-09-28 -### Fixed - - Segfault that occurs when passwd entry missing in docker - -## [1.1.4] - 2021-09-26 -### Changed - - There are no longer any known panics within the code, all possible panics - with whoami are now considered bugs. - - If any of the primary functions return an empty string, whoami should now - return "Unknown" or"unknown", or for `hostname()`, "localhost". - -### Fixed - - Panicking in situations where certain files don't exist / OS functions fail. - -## [1.1.3] - 2021-08-17 -### Fixed - - Circumstance where whoami points to invalid memory on Linux. - -## [1.1.2] - 2021-04-03 -### Fixed - - Not parsing the gecos field properly on unix systems (affects the - `realname()` and `realname_os()` functions; they will no longer return - extraneous commas on some systems). - -## [1.1.1] - 2021-03-13 -### Fixed - - Not compiling on target `x86_64-pc-windows-gnu`. - -## [1.1.0] - 2021-01-17 -### Added - - `lang()` function which returns an iterator over user's preferred language(s) - -## [1.0.3] - 2020-12-31 -### Fixed - - Link to logo in documentation. - -## [1.0.2] - 2020-12-31 -### Changed - - `distro()` on Windows now returns more detailed version. - -## [1.0.1] - 2020-12-16 -### Added - - Official support for BSD and variants - -### Fixed - - `platform()` will now return `Platform::Bsd` when running BSD. - - Misaligned address error on FreeBSD when calling `username()`. - -## [1.0.0] - 2020-11-23 -### Removed - - `Platform::Dive` and `DesktopEnv::Dive`, as that was an OS idea not a real OS - - Explicit support for `stdweb`, now built on `web-sys`/`wasm-bindgen`. - -## [0.9.0] - 2020-06-24 -### Added - - `stdweb` and `wasm-bindgen` support - - Versions of `-> String` functions that return `OsString`s: - - `devicename_os()` - - `distro_os()` - - `hostname_os()` - - `realname_os()` - - `username_os()` - -### Changed - - Renamed `DesktopEnv::Mac` to `DesktopEnv::Aqua` - - Renamed `DesktopEnv::Wasm` to `DesktopEnv::WebBrowser` - - Renamed `DesktopEnv::Redox` to `DesktopEnv::Orbital` - - Renamed `DesktopEnv::Fuchsia` to `DesktopEnv::Ermine` - - Renamed `Platform::FreeBsd` to `Platform::Bsd` - - Renamed `env()` to `desktop_env()` - - Renamed `host()` to `devicename()` - - Renamed `os()` to `distro()` - - Renamed `user()` to `realname()` - -### Fixed - - Inconsistencies on Windows - - MacOS running commands instead of using native APIs (this results in speed - improvements on MacOS) - - One of the Linux functions also using commands instead of native APIs (faster) - -### Contributors -Thanks to everyone who contributed to make this version of whoami possible! - -- [AldaronLau](https://github.com/AldaronLau) -- [Vlad-Shcherbina](https://github.com/Vlad-Shcherbina) - -## [0.8.2] - 2020-06-11 -### Changed - - Windows `host()` and `hostname()` now behave like they do on Linux and MacOS - -### Fixed - - Windows FFI Undefined Behavior because of not checking for errors - - Cross-compiling from Linux to Windows not working - -## [0.8.1] - 2020-02-22 -### Fixed - - Remove unnecessary use of `to_mut()` on `Cow`s returned from - `String::from_utf8_lossy()`. - -## [0.8.0] - 2020-02-21 -### Added - - Detection for KDE desktop environment. - -### Changed - - Unknown desktop environment may now contain lowercase characters. - -### Fixed - - No longer unwraps in any place where bad data from the OS could cause - a panic. - -## [0.7.0] - 2019-12-21 -### Removed - - `stdweb` dependency when targetting web assembly. - -### Changed - - All public enums now have the attribute `#[non_exhaustive]` and derive - `Debug`. - -### Fixed - - Some out-of-date documentation - -## [0.6.0] - 2019-10-25 -### Added - - Web Assembly support. - -### Removed - - `Platform::Web` variant of enum, use `env()` if you need to. - -### Changed - - `platform()` is no longer a const fn (needed for wasm platform - detection). - -## [0.5.3] - 2019-07-18 -### Changed - - Now uses a more modern Rust coding style (replace `::std::` with `std::`). - - Now uses a more modern Rust coding style with `mem::MaybeUninit`. - - `impl Display` for desktop environment now uses proper capitalization. - - Don't depend on `libc` anymore. -### Fixed - - Fancy Names not working on Windows - - `user()` now uses Windows Display Name on Windows rather than the username. - - `host()` now uses Windows Name DNS Fully Qualified rather than the hostname. - -## [0.5.2] - 2019-05-12 -### Fixed - - Fixed more broken links! - -## [0.5.1] - 2019-05-12 -### Fixed - - Clippy lint warning: change `expect(&format!("…"))` to `expect("…")` for optimization in 2 cases. - - Fixed broken links - -## [0.5.0] - 2019-03-17 -### Added - - `Platform` enum with corresponding `platform()` function. - - `Dive`, `Fuchsia`, and `Redox` to `DesktopEnv` enum. -### Changed - - Started using `const fn` for some functions. - -## [0.4.1] - 2019-01-12 -### Fixed - - Fixed README errors. - -## [0.4.0] - 2019-01-12 -### Added - - MacOS support. -### Changed - - `env` on Ubuntu now returns DesktopEnv::Ubuntu instead of DesktopEnv::Other("UBUNTU") - - Split off the binary into `whome` (who me?) crate - -## [0.3.0] - 2019-01-04 -### Added - - Added more fallbacks. -### Changed - - Rename realname -> user - - Rename computer -> host -### Fixed - - Fix typo for uknown -> unknown. - -## [0.2.4] - 2018-12-04 -### Fixed - - Works now on platforms that use u8 instead of i8 for chars (like ARM). - -## [0.2.3] - 2018-11-26 -### Fixed - - Trailing newline on Windows. - -## [0.2.2] - 2018-06-02 -### Fixed - - Typo in markdown. - -## [0.2.1] - 2018-06-02 -### Fixed - - Undefined behavior on Linux. - -## [0.2.0] - 2017-12-28 -### Added - - Windows support. - -## [0.1.1] - 2017-08-04 -### Fixed - - Something in the markdown. - -## [0.1.0] - 2017-08-04 -### Added - - Published to crates.io. - -[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ -[Semantic Versioning]: https://github.com/AldaronLau/semver/ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog], and this project adheres to +[Semantic Versioning]. + +## [1.4.1] - 2023-06-25 +### Fixed + - License files not being included in package on crates.io + +## [1.4.0] - 2023-03-12 +### Added + - Support for Illumos + +## [1.3.0] - 2022-12-28 +### Added + - `Arch` enum listing CPU architectures + - `Width` enum listing CPU architecture address widths + - `arch()` function which returns an `Arch` type representing a CPU + architecture + - `Arch::width()` method which returns the address width of a CPU architecture + - *`web`* feature (enabled by default). Disabling this feature allows you to + use wasm32-unknown-unknown with whoami outside of the browser with a mock + implementation. + - Officially support compiling to WASI or Daku WebAssembly platforms; + functionality not supported yet. + - Convenience `Result` type alias. + +### Changed + - Modernized and cleaned up code style + +### Fixed + - Handling of `lang()` when `$LANG` environment variable on unix set to "C", + causing duplicated iterator elements `["C", "C"]`; now produces `["en-US"]`. + - WhoAmI reporting "Safari" when running in Chrome/Chromium browser + - WhoAmI reporting "Edg" when running in Edge browser (now reports "Edge") + - WhoAmI reporting "OPR" when running in Opera browser (now reports "Opera") + - WhoAmI reporting "Mozilla" when running in GNOME web browser (now reports + "GNOME Web") + +## [1.2.3] - 2022-09-12 +### Fixed + - WebAssembly target requiring older versions of dependencies + +## [1.2.2] - 2022-09-05 +### Added + - More details to the method documentation + +### Changed + - WhoAmI now has an official MSRV of Rust 1.40.0 + - `whoami::hostname()` is now normalized to lowercase + +## [1.2.1] - 2021-11-24 +### Fixed + - The Windows GNU target support being broken + +## [1.2.0] - 2021-11-06 +### Added + - Derives for `Clone`, `PartialEq` and `Eq` on `DesktopEnv` and `Platform` + +### Changed + - Lower MSRV for Windows + +## [1.1.5] - 2021-09-28 +### Fixed + - Segfault that occurs when passwd entry missing in docker + +## [1.1.4] - 2021-09-26 +### Changed + - There are no longer any known panics within the code, all possible panics + with whoami are now considered bugs. + - If any of the primary functions return an empty string, whoami should now + return "Unknown" or"unknown", or for `hostname()`, "localhost". + +### Fixed + - Panicking in situations where certain files don't exist / OS functions fail. + +## [1.1.3] - 2021-08-17 +### Fixed + - Circumstance where whoami points to invalid memory on Linux. + +## [1.1.2] - 2021-04-03 +### Fixed + - Not parsing the gecos field properly on unix systems (affects the + `realname()` and `realname_os()` functions; they will no longer return + extraneous commas on some systems). + +## [1.1.1] - 2021-03-13 +### Fixed + - Not compiling on target `x86_64-pc-windows-gnu`. + +## [1.1.0] - 2021-01-17 +### Added + - `lang()` function which returns an iterator over user's preferred language(s) + +## [1.0.3] - 2020-12-31 +### Fixed + - Link to logo in documentation. + +## [1.0.2] - 2020-12-31 +### Changed + - `distro()` on Windows now returns more detailed version. + +## [1.0.1] - 2020-12-16 +### Added + - Official support for BSD and variants + +### Fixed + - `platform()` will now return `Platform::Bsd` when running BSD. + - Misaligned address error on FreeBSD when calling `username()`. + +## [1.0.0] - 2020-11-23 +### Removed + - `Platform::Dive` and `DesktopEnv::Dive`, as that was an OS idea not a real OS + - Explicit support for `stdweb`, now built on `web-sys`/`wasm-bindgen`. + +## [0.9.0] - 2020-06-24 +### Added + - `stdweb` and `wasm-bindgen` support + - Versions of `-> String` functions that return `OsString`s: + - `devicename_os()` + - `distro_os()` + - `hostname_os()` + - `realname_os()` + - `username_os()` + +### Changed + - Renamed `DesktopEnv::Mac` to `DesktopEnv::Aqua` + - Renamed `DesktopEnv::Wasm` to `DesktopEnv::WebBrowser` + - Renamed `DesktopEnv::Redox` to `DesktopEnv::Orbital` + - Renamed `DesktopEnv::Fuchsia` to `DesktopEnv::Ermine` + - Renamed `Platform::FreeBsd` to `Platform::Bsd` + - Renamed `env()` to `desktop_env()` + - Renamed `host()` to `devicename()` + - Renamed `os()` to `distro()` + - Renamed `user()` to `realname()` + +### Fixed + - Inconsistencies on Windows + - MacOS running commands instead of using native APIs (this results in speed + improvements on MacOS) + - One of the Linux functions also using commands instead of native APIs (faster) + +### Contributors +Thanks to everyone who contributed to make this version of whoami possible! + +- [AldaronLau](https://github.com/AldaronLau) +- [Vlad-Shcherbina](https://github.com/Vlad-Shcherbina) + +## [0.8.2] - 2020-06-11 +### Changed + - Windows `host()` and `hostname()` now behave like they do on Linux and MacOS + +### Fixed + - Windows FFI Undefined Behavior because of not checking for errors + - Cross-compiling from Linux to Windows not working + +## [0.8.1] - 2020-02-22 +### Fixed + - Remove unnecessary use of `to_mut()` on `Cow`s returned from + `String::from_utf8_lossy()`. + +## [0.8.0] - 2020-02-21 +### Added + - Detection for KDE desktop environment. + +### Changed + - Unknown desktop environment may now contain lowercase characters. + +### Fixed + - No longer unwraps in any place where bad data from the OS could cause + a panic. + +## [0.7.0] - 2019-12-21 +### Removed + - `stdweb` dependency when targetting web assembly. + +### Changed + - All public enums now have the attribute `#[non_exhaustive]` and derive + `Debug`. + +### Fixed + - Some out-of-date documentation + +## [0.6.0] - 2019-10-25 +### Added + - Web Assembly support. + +### Removed + - `Platform::Web` variant of enum, use `env()` if you need to. + +### Changed + - `platform()` is no longer a const fn (needed for wasm platform + detection). + +## [0.5.3] - 2019-07-18 +### Changed + - Now uses a more modern Rust coding style (replace `::std::` with `std::`). + - Now uses a more modern Rust coding style with `mem::MaybeUninit`. + - `impl Display` for desktop environment now uses proper capitalization. + - Don't depend on `libc` anymore. +### Fixed + - Fancy Names not working on Windows + - `user()` now uses Windows Display Name on Windows rather than the username. + - `host()` now uses Windows Name DNS Fully Qualified rather than the hostname. + +## [0.5.2] - 2019-05-12 +### Fixed + - Fixed more broken links! + +## [0.5.1] - 2019-05-12 +### Fixed + - Clippy lint warning: change `expect(&format!("…"))` to `expect("…")` for optimization in 2 cases. + - Fixed broken links + +## [0.5.0] - 2019-03-17 +### Added + - `Platform` enum with corresponding `platform()` function. + - `Dive`, `Fuchsia`, and `Redox` to `DesktopEnv` enum. +### Changed + - Started using `const fn` for some functions. + +## [0.4.1] - 2019-01-12 +### Fixed + - Fixed README errors. + +## [0.4.0] - 2019-01-12 +### Added + - MacOS support. +### Changed + - `env` on Ubuntu now returns DesktopEnv::Ubuntu instead of DesktopEnv::Other("UBUNTU") + - Split off the binary into `whome` (who me?) crate + +## [0.3.0] - 2019-01-04 +### Added + - Added more fallbacks. +### Changed + - Rename realname -> user + - Rename computer -> host +### Fixed + - Fix typo for uknown -> unknown. + +## [0.2.4] - 2018-12-04 +### Fixed + - Works now on platforms that use u8 instead of i8 for chars (like ARM). + +## [0.2.3] - 2018-11-26 +### Fixed + - Trailing newline on Windows. + +## [0.2.2] - 2018-06-02 +### Fixed + - Typo in markdown. + +## [0.2.1] - 2018-06-02 +### Fixed + - Undefined behavior on Linux. + +## [0.2.0] - 2017-12-28 +### Added + - Windows support. + +## [0.1.1] - 2017-08-04 +### Fixed + - Something in the markdown. + +## [0.1.0] - 2017-08-04 +### Added + - Published to crates.io. + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ +[Semantic Versioning]: https://github.com/AldaronLau/semver/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b19a756..efdbb5b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,76 +1,76 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at aldaronlau@gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at aldaronlau@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8fc20ef..635bae5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,22 @@ -# Contributing -Anyone is welcome to contribute! You can [open an issue], -[Post to GitHub Discussions] or [send me an email] about anything related to -this project. You may also [open a PR]. I don't require PRs to be formatted in -a specific manner, since I'll run it through rustfmt after the merge anyway. If -you're going to work on a PR, it would be preferred to let me know ahead of time -(unless it's a quick fix), and open a draft PR if it's a large one. Then I'll -assign the issue to you. Otherwise, I can't guarantee I won't duplicate your -work. If I can't contact you within a week, I may unassign you and finish your -work (opening a Draft PR on this repository puts your code under this crate's -license). - -If you open a bug report, you can usually expect it to be fixed within a week. -If you open a feature request it may stay open indefinitely, until I need it -too. I mark feature requests as "enhancements" on GitHub issues. - -Happy coding! - -[open an issue]: https://github.com/ardaku/whoami/issues -[send me an email]: mailto:aldaronlau@gmail.com -[open a PR]: https://github.com/ardaku/whoami/pulls -[Post to GitHub Discussions]: https://github.com/ardaku/whoami/discussions +# Contributing +Anyone is welcome to contribute! You can [open an issue], +[Post to GitHub Discussions] or [send me an email] about anything related to +this project. You may also [open a PR]. I don't require PRs to be formatted in +a specific manner, since I'll run it through rustfmt after the merge anyway. If +you're going to work on a PR, it would be preferred to let me know ahead of time +(unless it's a quick fix), and open a draft PR if it's a large one. Then I'll +assign the issue to you. Otherwise, I can't guarantee I won't duplicate your +work. If I can't contact you within a week, I may unassign you and finish your +work (opening a Draft PR on this repository puts your code under this crate's +license). + +If you open a bug report, you can usually expect it to be fixed within a week. +If you open a feature request it may stay open indefinitely, until I need it +too. I mark feature requests as "enhancements" on GitHub issues. + +Happy coding! + +[open an issue]: https://github.com/ardaku/whoami/issues +[send me an email]: mailto:aldaronlau@gmail.com +[open a PR]: https://github.com/ardaku/whoami/pulls +[Post to GitHub Discussions]: https://github.com/ardaku/whoami/discussions diff --git a/Cargo.toml b/Cargo.toml index 21b9a91..44941be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,41 +1,44 @@ -[package] -name = "whoami" -version = "1.4.1" -edition = "2018" -license = "Apache-2.0 OR BSL-1.0 OR MIT" -documentation = "https://docs.rs/whoami" -homepage = "https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md" -repository = "https://github.com/ardaku/whoami" -readme = "README.md" -description = "Retrieve the current user and environment." -keywords = ["user", "username", "whoami", "platform", "detect"] -categories = [ - "os", - "wasm", - "internationalization", - "localization", - "value-formatting", -] -include = [ - "LICENSE_APACHE", - "LICENSE_BOOST", - "LICENSE_MIT", - "README.md", - "src/*", -] -rust-version = "1.40" - -# Target-specific dependency required to work with wasm-bindgen -[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.web-sys] -version = "0.3" -features = ["Navigator", "Document", "Window", "Location"] -optional = true -[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.wasm-bindgen] -version = "0.2" -optional = true - -[features] -default = ["web"] -# Enabling this feature indicates that the wasm32-unknown-unknown target should -# be assumed to be in a web environment where it can call DOM APIs. -web = ["web-sys", "wasm-bindgen"] +[package] +name = "whoami" +version = "1.4.1" +edition = "2018" +license = "Apache-2.0 OR BSL-1.0 OR MIT" +documentation = "https://docs.rs/whoami" +homepage = "https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md" +repository = "https://github.com/ardaku/whoami" +readme = "README.md" +description = "Retrieve the current user and environment." +keywords = ["user", "username", "whoami", "platform", "detect"] +categories = [ + "os", + "wasm", + "internationalization", + "localization", + "value-formatting", +] +include = [ + "LICENSE_APACHE", + "LICENSE_BOOST", + "LICENSE_MIT", + "README.md", + "src/*", +] +rust-version = "1.40" + +# Target-specific dependency required to work with wasm-bindgen +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.web-sys] +version = "0.3" +features = ["Navigator", "Document", "Window", "Location"] +optional = true +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.wasm-bindgen] +version = "0.2" +optional = true + +[features] +default = ["web"] +# Enabling this feature indicates that the wasm32-unknown-unknown target should +# be assumed to be in a web environment where it can call DOM APIs. +web = ["web-sys", "wasm-bindgen"] + +[dependencies] +ansi_term = "0.12.0" \ No newline at end of file diff --git a/LICENSE_APACHE b/LICENSE_APACHE index 1b5ec8b..a2ce4d9 100644 --- a/LICENSE_APACHE +++ b/LICENSE_APACHE @@ -1,176 +1,176 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE_BOOST b/LICENSE_BOOST index 36b7cd9..1dad8e9 100644 --- a/LICENSE_BOOST +++ b/LICENSE_BOOST @@ -1,23 +1,23 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/LICENSE_MIT b/LICENSE_MIT index 9cf1062..9dccfa4 100644 --- a/LICENSE_MIT +++ b/LICENSE_MIT @@ -1,19 +1,19 @@ -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index b8e60d6..ef9e741 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,93 @@ -![WhoAmI Logo](https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg) - -#### [Changelog][3] | [Source][4] | [Getting Started][5] - -[![tests](https://github.com/ardaku/whoami/actions/workflows/ci.yml/badge.svg)](https://github.com/ardaku/whoami/actions/workflows/ci.yml) -[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/ardaku/whoami)](https://github.com/ardaku/whoami/) -[![GitHub contributors](https://img.shields.io/github/contributors/ardaku/whoami)](https://github.com/ardaku/whoami/graphs/contributors) -[![Crates.io](https://img.shields.io/crates/v/whoami)](https://crates.io/crates/whoami) -[![Crates.io](https://img.shields.io/crates/d/whoami)](https://crates.io/crates/whoami) -[![Crates.io (recent)](https://img.shields.io/crates/dr/whoami)](https://crates.io/crates/whoami) -[![Crates.io](https://img.shields.io/crates/l/whoami)](https://github.com/ardaku/whoami/search?l=Text&q=license) -[![Docs.rs](https://docs.rs/whoami/badge.svg)](https://docs.rs/whoami/) - -Retrieve the current user and environment through simple functions. - -Check out the [documentation][0] for examples. - -### Features - - Get the user's full name - - Get the user's username - - Get the user's preferred language(s) - - Get the devices's hostname - - Get the devices's "pretty" or "fancy" name - - Get the devices's desktop environment - - Get the devices's OS name and version - - Get the devices's platform name - - Get the devices's CPU architecture and its width - -### Supported Platforms -WhoAmI targets all platforms that can run Rust, including: - - Linux - - Windows - - Mac OS - - BSD variants (FreeBSD, others) - - [Web Assembly](https://github.com/ardaku/whoami/blob/stable/WASM.md) - - Mock implementation - - Web Browser - DOM - - WASI (Wasite/Quantii, others) **mock implementation, full implementation planned later** - - Daku (Ardaku/Quantii, others) **mock implementation, full implementation planned later** - - Illumos variants (SmartOS, OmniOS, others) **may partially or fully work - but untested** - - Android **may partially or fully work - but untested, planned later** - - iOS **planned later** - - Redox **planned later** - - Fuchsia **planned later** - - Various game consoles **planned later** - - Others? (make a PR or open an issue) - -## MSRV -WhoAmI 1.x.y targets Rust 1.40.0 stable and later, and the 1.x.y track will -be maintained at least until the release of the Rust 2024 edition. - -The MSRV will only be updated on major version bumps, and version 2.0.0 will -target Rust 1.65.0 and later to make use of the `let else` syntax. - -## Binary -[whome](https://crates.io/crates/whome): `whoami` command RiR (Re-written in -Rust) that depends on this crate. - -## License -Copyright © 2017-2023 The WhoAmI Contributors. - -Licensed under any of - - Apache License, Version 2.0, ([LICENSE_APACHE][7] - or [https://www.apache.org/licenses/LICENSE-2.0][8]) - - Boost Software License, Version 1.0, ([LICENSE_BOOST][11] - or [https://www.boost.org/LICENSE_1_0.txt][12]) - - MIT License, ([LICENSE_MIT][9] or [https://mit-license.org/][10]) - -at your option. - -### Contribution -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -licensed as described above, without any additional terms or conditions. - -## Help -If you want help using or contributing to this library, feel free to send me an -email at [aldaronlau@gmail.com][13]. - -[0]: https://docs.rs/whoami -[1]: https://crates.io/crates/whoami -[2]: https://github.com/ardaku/whoami/actions?query=workflow%3Atests -[3]: https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md -[4]: https://github.com/ardaku/whoami/ -[5]: https://docs.rs/whoami#getting-started -[6]: https://aldaronlau.com/ -[7]: https://github.com/ardaku/whoami/blob/stable/LICENSE_APACHE -[8]: https://www.apache.org/licenses/LICENSE-2.0 -[9]: https://github.com/ardaku/whoami/blob/stable/LICENSE_MIT -[10]: https://mit-license.org/ -[11]: https://github.com/ardaku/whoami/blob/stable/LICENSE_BOOST -[12]: https://www.boost.org/LICENSE_1_0.txt -[13]: mailto:aldaronlau@gmail.com +![WhoAmI Logo](https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg) + +#### [Changelog][3] | [Source][4] | [Getting Started][5] + +[![tests](https://github.com/ardaku/whoami/actions/workflows/ci.yml/badge.svg)](https://github.com/ardaku/whoami/actions/workflows/ci.yml) +[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/ardaku/whoami)](https://github.com/ardaku/whoami/) +[![GitHub contributors](https://img.shields.io/github/contributors/ardaku/whoami)](https://github.com/ardaku/whoami/graphs/contributors) +[![Crates.io](https://img.shields.io/crates/v/whoami)](https://crates.io/crates/whoami) +[![Crates.io](https://img.shields.io/crates/d/whoami)](https://crates.io/crates/whoami) +[![Crates.io (recent)](https://img.shields.io/crates/dr/whoami)](https://crates.io/crates/whoami) +[![Crates.io](https://img.shields.io/crates/l/whoami)](https://github.com/ardaku/whoami/search?l=Text&q=license) +[![Docs.rs](https://docs.rs/whoami/badge.svg)](https://docs.rs/whoami/) + +Retrieve the current user and environment through simple functions. + +Check out the [documentation][0] for examples. + +### Features + - Get the user's full name + - Get the user's username + - Get the user's preferred language(s) + - Get the devices's hostname + - Get the devices's "pretty" or "fancy" name + - Get the devices's desktop environment + - Get the devices's OS name and version + - Get the devices's platform name + - Get the devices's CPU architecture and its width + +### Supported Platforms +WhoAmI targets all platforms that can run Rust, including: + - Linux + - Windows + - Mac OS + - BSD variants (FreeBSD, others) + - [Web Assembly](https://github.com/ardaku/whoami/blob/stable/WASM.md) + - Mock implementation + - Web Browser - DOM + - WASI (Wasite/Quantii, others) **mock implementation, full implementation planned later** + - Daku (Ardaku/Quantii, others) **mock implementation, full implementation planned later** + - Illumos variants (SmartOS, OmniOS, others) **may partially or fully work - but untested** + - Android **may partially or fully work - but untested, planned later** + - iOS **planned later** + - Redox **planned later** + - Fuchsia **planned later** + - Various game consoles **planned later** + - Others? (make a PR or open an issue) + +## MSRV +WhoAmI 1.x.y targets Rust 1.40.0 stable and later, and the 1.x.y track will +be maintained at least until the release of the Rust 2024 edition. + +The MSRV will only be updated on major version bumps, and version 2.0.0 will +target Rust 1.65.0 and later to make use of the `let else` syntax. + +## Binary +[whome](https://crates.io/crates/whome): `whoami` command RiR (Re-written in +Rust) that depends on this crate. + +## License +Copyright © 2017-2023 The WhoAmI Contributors. + +Licensed under any of + - Apache License, Version 2.0, ([LICENSE_APACHE][7] + or [https://www.apache.org/licenses/LICENSE-2.0][8]) + - Boost Software License, Version 1.0, ([LICENSE_BOOST][11] + or [https://www.boost.org/LICENSE_1_0.txt][12]) + - MIT License, ([LICENSE_MIT][9] or [https://mit-license.org/][10]) + +at your option. + +### Contribution +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +licensed as described above, without any additional terms or conditions. + +## Help +If you want help using or contributing to this library, feel free to send me an +email at [aldaronlau@gmail.com][13]. + +[0]: https://docs.rs/whoami +[1]: https://crates.io/crates/whoami +[2]: https://github.com/ardaku/whoami/actions?query=workflow%3Atests +[3]: https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md +[4]: https://github.com/ardaku/whoami/ +[5]: https://docs.rs/whoami#getting-started +[6]: https://aldaronlau.com/ +[7]: https://github.com/ardaku/whoami/blob/stable/LICENSE_APACHE +[8]: https://www.apache.org/licenses/LICENSE-2.0 +[9]: https://github.com/ardaku/whoami/blob/stable/LICENSE_MIT +[10]: https://mit-license.org/ +[11]: https://github.com/ardaku/whoami/blob/stable/LICENSE_BOOST +[12]: https://www.boost.org/LICENSE_1_0.txt +[13]: mailto:aldaronlau@gmail.com diff --git a/WASM.md b/WASM.md index 1cd9995..c38c95c 100644 --- a/WASM.md +++ b/WASM.md @@ -1,48 +1,48 @@ -# WhoAmI WebAssembly Documentation - -## Web (Browser) -By default, when WhoAmI is compiled for Wasm32 unknown (neither -wasi or -daku), -WhoAmI links to web-sys and defaults values to browser information: - - - `realname()`: "Anonymous" - - `username()`: "anonymous" - - `lang()`: Browser preferred language list - - `devicename()`: Browser name (Example: "Firefox 110.0") - - `hostname()`: "localhost" - - `platform()`: Host operating system by view of browser (Example: "Linux") - - `distro()`: Host distro by view of browser (Example "Unknown Linux") - - `desktop_env()`: "Web Browser" - - `arch()`: "wasm32" - -## Mock -If you compile WhoAmI with `default-features = false`, WhoAmI will not bind to -web-sys, and will instead return these mock values: - - - `realname()`: "Anonymous" - - `username()`: "anonymous" - - `lang()`: "en-US" - - `devicename()`: "Unknown" - - `hostname()`: "localhost" - - `platform()`: "Unknown" - - `distro()`: "Emulated" - - `desktop_env()`: "Unknown WebAssembly" - - `arch()`: "wasm32" - -## Wasi (Wasite) -Building WhoAmI targeting Wasi will assume the -[wasite](https://ardaku.org/wasite/env_vars.html) environment variables are set, -as Wasi alone does not currently support the functionality WhoAmI requires. - - - `realname()`: `$USER` - - `username()`: `$USER` - - `lang()`: `$LANGS` - - `devicename()`: `$NAME` - - `hostname()`: `$HOSTNAME` - - `platform()`: "Wasite" - - `distro()`: "Unknown wasi" - - `desktop_env()`: "Unknown wasite" - - `arch()`: "wasm32" - -## Daku (Quantii, other Ardaku environments) -WhoAmi will depend on currently unstable portals in the -[Daku](https://ardaku.org/daku/) specification. +# WhoAmI WebAssembly Documentation + +## Web (Browser) +By default, when WhoAmI is compiled for Wasm32 unknown (neither -wasi or -daku), +WhoAmI links to web-sys and defaults values to browser information: + + - `realname()`: "Anonymous" + - `username()`: "anonymous" + - `lang()`: Browser preferred language list + - `devicename()`: Browser name (Example: "Firefox 110.0") + - `hostname()`: "localhost" + - `platform()`: Host operating system by view of browser (Example: "Linux") + - `distro()`: Host distro by view of browser (Example "Unknown Linux") + - `desktop_env()`: "Web Browser" + - `arch()`: "wasm32" + +## Mock +If you compile WhoAmI with `default-features = false`, WhoAmI will not bind to +web-sys, and will instead return these mock values: + + - `realname()`: "Anonymous" + - `username()`: "anonymous" + - `lang()`: "en-US" + - `devicename()`: "Unknown" + - `hostname()`: "localhost" + - `platform()`: "Unknown" + - `distro()`: "Emulated" + - `desktop_env()`: "Unknown WebAssembly" + - `arch()`: "wasm32" + +## Wasi (Wasite) +Building WhoAmI targeting Wasi will assume the +[wasite](https://ardaku.org/wasite/env_vars.html) environment variables are set, +as Wasi alone does not currently support the functionality WhoAmI requires. + + - `realname()`: `$USER` + - `username()`: `$USER` + - `lang()`: `$LANGS` + - `devicename()`: `$NAME` + - `hostname()`: `$HOSTNAME` + - `platform()`: "Wasite" + - `distro()`: "Unknown wasi" + - `desktop_env()`: "Unknown wasite" + - `arch()`: "wasm32" + +## Daku (Quantii, other Ardaku environments) +WhoAmi will depend on currently unstable portals in the +[Daku](https://ardaku.org/daku/) specification. diff --git a/examples/os-strings.rs b/examples/os-strings.rs index 158248d..abbf5d2 100644 --- a/examples/os-strings.rs +++ b/examples/os-strings.rs @@ -1,42 +1,42 @@ -fn main() { - println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); - println!(); - println!( - "User's Name whoami::realname_os(): {:?}", - whoami::realname_os() - ); - println!( - "User's Username whoami::username_os(): {:?}", - whoami::username() - ); - println!( - "User's Language whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - ); - println!( - "Device's Pretty Name whoami::devicename_os(): {:?}", - whoami::devicename() - ); - println!( - "Device's Hostname whoami::hostname_os(): {:?}", - whoami::hostname() - ); - println!( - "Device's Platform whoami::platform_os(): {:?}", - whoami::platform() - ); - println!( - "Device's OS Distro whoami::distro_os(): {:?}", - whoami::distro() - ); - println!( - "Device's Desktop Env. whoami::desktop_env(): {:?}", - whoami::desktop_env() - ); - println!( - "Device's CPU Arch whoami::arch(): {:?}", - whoami::arch() - ); -} +fn main() { + println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); + println!(); + println!( + "User's Name whoami::realname_os(): {:?}", + whoami::realname_os() + ); + println!( + "User's Username whoami::username_os(): {:?}", + whoami::username() + ); + println!( + "User's Language whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + ); + println!( + "Device's Pretty Name whoami::devicename_os(): {:?}", + whoami::devicename() + ); + println!( + "Device's Hostname whoami::hostname_os(): {:?}", + whoami::hostname() + ); + println!( + "Device's Platform whoami::platform_os(): {:?}", + whoami::platform() + ); + println!( + "Device's OS Distro whoami::distro_os(): {:?}", + whoami::distro() + ); + println!( + "Device's Desktop Env. whoami::desktop_env(): {:?}", + whoami::desktop_env() + ); + println!( + "Device's CPU Arch whoami::arch(): {:?}", + whoami::arch() + ); +} diff --git a/examples/web/Cargo.toml b/examples/web/Cargo.toml index 2f74f75..c552342 100644 --- a/examples/web/Cargo.toml +++ b/examples/web/Cargo.toml @@ -1,36 +1,36 @@ -[package] -name = "whoami_web" -version = "0.1.0" -authors = ["Jeron Aldaron Lau "] -edition = "2021" - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -default = ["console_error_panic_hook"] - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for -# code size when deploying. -[dependencies.console_error_panic_hook] -version = "0.1" -optional = true - -# wasm-bindgen lets us export our main function to the javascript that runs the -# web assembly module. -[dependencies.wasm-bindgen] -version = "0.2" - -# The `web-sys` crate lets us log in the web console. -[dependencies.web-sys] -version = "0.3" -features = ["console"] - -# `whoami` - the crate we're testing! -[dependencies.whoami] -path = "../../" - -[profile.release] -opt-level = "s" # Tell `rustc` to optimize for small code size. +[package] +name = "whoami_web" +version = "0.1.0" +authors = ["Jeron Aldaron Lau "] +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["console_error_panic_hook"] + +# The `console_error_panic_hook` crate provides better debugging of panics by +# logging them with `console.error`. This is great for development, but requires +# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for +# code size when deploying. +[dependencies.console_error_panic_hook] +version = "0.1" +optional = true + +# wasm-bindgen lets us export our main function to the javascript that runs the +# web assembly module. +[dependencies.wasm-bindgen] +version = "0.2" + +# The `web-sys` crate lets us log in the web console. +[dependencies.web-sys] +version = "0.3" +features = ["console"] + +# `whoami` - the crate we're testing! +[dependencies.whoami] +path = "../../" + +[profile.release] +opt-level = "s" # Tell `rustc` to optimize for small code size. diff --git a/examples/web/README.md b/examples/web/README.md index b008fc0..61d1797 100644 --- a/examples/web/README.md +++ b/examples/web/README.md @@ -1,15 +1,15 @@ -# A Web Example - -## Install `wasm-pack` and `http` -```bash -curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -cargo install https -``` - -## Build & Run Web Server -```bash -wasm-pack build --target web && http . -``` - -Now, open http://localhost:8000/ in your web browser and check the javascript -console. +# A Web Example + +## Install `wasm-pack` and `http` +```bash +curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh +cargo install https +``` + +## Build & Run Web Server +```bash +wasm-pack build --target web && http . +``` + +Now, open http://localhost:8000/ in your web browser and check the javascript +console. diff --git a/examples/web/index.html b/examples/web/index.html index b23bac6..d49a157 100644 --- a/examples/web/index.html +++ b/examples/web/index.html @@ -1,14 +1,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/examples/web/rust-toolchain b/examples/web/rust-toolchain index 292fe49..ec19b69 100644 --- a/examples/web/rust-toolchain +++ b/examples/web/rust-toolchain @@ -1,2 +1,2 @@ -[toolchain] -channel = "stable" +[toolchain] +channel = "stable" diff --git a/examples/web/src/lib.rs b/examples/web/src/lib.rs index 57f996b..cc783b8 100644 --- a/examples/web/src/lib.rs +++ b/examples/web/src/lib.rs @@ -1,57 +1,57 @@ -use wasm_bindgen::prelude::*; - -fn log(text: String) { - web_sys::console::log_1(&text.into()) -} - -#[wasm_bindgen] -pub fn main() { - // When the `console_error_panic_hook` feature is enabled, we can call the - // `set_panic_hook` function at least once during initialization, and then - // we will get better error messages if our code ever panics. - // - // For more details see - // https://github.com/rustwasm/console_error_panic_hook#readme - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); - - // Print out code from regular example. - log(format!( - "User's Name whoami::realname(): {}", - whoami::realname(), - )); - log(format!( - "User's Username whoami::username(): {}", - whoami::username(), - )); - log(format!( - "User's Languages whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - )); - log(format!( - "Device's Pretty Name whoami::devicename(): {}", - whoami::devicename(), - )); - log(format!( - "Device's Hostname whoami::hostname(): {}", - whoami::hostname(), - )); - log(format!( - "Device's Platform whoami::platform(): {}", - whoami::platform(), - )); - log(format!( - "Device's OS Distro whoami::distro(): {}", - whoami::distro(), - )); - log(format!( - "Device's Desktop Env. whoami::desktop_env(): {}", - whoami::desktop_env(), - )); - log(format!( - "Device's CPU Arch whoami::arch(): {}", - whoami::arch(), - )); -} +use wasm_bindgen::prelude::*; + +fn log(text: String) { + web_sys::console::log_1(&text.into()) +} + +#[wasm_bindgen] +pub fn main() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); + + // Print out code from regular example. + log(format!( + "User's Name whoami::realname(): {}", + whoami::realname(), + )); + log(format!( + "User's Username whoami::username(): {}", + whoami::username(), + )); + log(format!( + "User's Languages whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + )); + log(format!( + "Device's Pretty Name whoami::devicename(): {}", + whoami::devicename(), + )); + log(format!( + "Device's Hostname whoami::hostname(): {}", + whoami::hostname(), + )); + log(format!( + "Device's Platform whoami::platform(): {}", + whoami::platform(), + )); + log(format!( + "Device's OS Distro whoami::distro(): {}", + whoami::distro(), + )); + log(format!( + "Device's Desktop Env. whoami::desktop_env(): {}", + whoami::desktop_env(), + )); + log(format!( + "Device's CPU Arch whoami::arch(): {}", + whoami::arch(), + )); +} diff --git a/examples/whoami-demo.rs b/examples/whoami-demo.rs index 3472fd3..d5dd518 100644 --- a/examples/whoami-demo.rs +++ b/examples/whoami-demo.rs @@ -1,42 +1,42 @@ -fn main() { - println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); - println!(); - println!( - "User's Name whoami::realname(): {}", - whoami::realname(), - ); - println!( - "User's Username whoami::username(): {}", - whoami::username(), - ); - println!( - "User's Language whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - ); - println!( - "Device's Pretty Name whoami::devicename(): {}", - whoami::devicename(), - ); - println!( - "Device's Hostname whoami::hostname(): {}", - whoami::hostname(), - ); - println!( - "Device's Platform whoami::platform(): {}", - whoami::platform(), - ); - println!( - "Device's OS Distro whoami::distro(): {}", - whoami::distro(), - ); - println!( - "Device's Desktop Env. whoami::desktop_env(): {}", - whoami::desktop_env(), - ); - println!( - "Device's CPU Arch whoami::arch(): {}", - whoami::arch(), - ); -} +fn main() { + println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); + println!(); + println!( + "User's Name whoami::realname(): {}", + whoami::realname(), + ); + println!( + "User's Username whoami::username(): {}", + whoami::username(), + ); + println!( + "User's Language whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + ); + println!( + "Device's Pretty Name whoami::devicename(): {}", + whoami::devicename(), + ); + println!( + "Device's Hostname whoami::hostname(): {}", + whoami::hostname(), + ); + println!( + "Device's Platform whoami::platform(): {}", + whoami::platform(), + ); + println!( + "Device's OS Distro whoami::distro(): {}", + whoami::distro(), + ); + println!( + "Device's Desktop Env. whoami::desktop_env(): {}", + whoami::desktop_env(), + ); + println!( + "Device's CPU Arch whoami::arch(): {}", + whoami::arch(), + ); +} diff --git a/res/icon.svg b/res/icon.svg index 71fc460..6772500 100644 --- a/res/icon.svg +++ b/res/icon.svg @@ -1,108 +1,108 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/rust-toolchain b/rust-toolchain index aacef61..8395338 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,2 +1,2 @@ -[toolchain] -channel = "1.40.0" +[toolchain] +channel = "1.40.0" diff --git a/src/disp.rs b/src/disp.rs new file mode 100644 index 0000000..5964369 --- /dev/null +++ b/src/disp.rs @@ -0,0 +1,250 @@ +use ansi_term::Colour; + +pub fn display_windows() -> &'static str { + r#" + .oodMMMM + .oodMMMMMMMMMMMMM + ..oodMMM MMMMMMMMMMMMMMMMMMM + oodMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM .----------------. .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + | | _____ _____ | || | _____ | || | ____ _____ | || | ________ | || | ____ | || | _____ _____ | || | _______ | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | ||_ _||_ _|| || | |_ _| | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | || ||_ _||_ _|| || | / ___ | | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | | /\ | | | || | | | | || | | \ | | | || | | | `. \ | || | / .--. \ | || | | | /\ | | | || | | (__ \_| | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | |/ \| | | || | | | | || | | |\ \| | | || | | | | | | || | | | | | | || | | |/ \| | | || | '.___`-. | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | /\ | | || | _| |_ | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | || | | /\ | | || | |`\____) | | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | |__/ \__| | || | |_____| | || ||_____|\____| | || | |________.' | || | `.____.' | || | |__/ \__| | || | |_______.' | | + `^^^^^^MMMMMMM MMMMMMMMMMMMMMMMMMM | | | || | | || | | || | | || | | || | | || | | | + ````^^^^ ^^MMMMMMMMMMMMMMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + ````^^^^^^MMMM '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_bsd() -> &'static str { + r#" + , , + /( )` + \ \___ / | + /- _ `-/ ' + (/\/ \ \ /\ + / / | ` \ + O O ) / | + `-^--'`< ' + (_.) _ ) / .----------------. .----------------. .----------------. + `.___/` / | .--------------. || .--------------. || .--------------. | + `-----' / | | ______ | || | _______ | || | ________ | | + <----. __ / __ \ | | |_ _ \ | || | / ___ | | || | |_ ___ `. | | + <----|====O)))==) \) /==== | | | |_) | | || | | (__ \_| | || | | | `. \ | | + <----' `--' `.__,' \ | | | __'. | || | '.___`-. | || | | | | | | | + | | | | _| |__) | | || | |`\____) | | || | _| |___.' / | | + \ / | | |_______/ | || | |_______.' | || | |________.' | | + ______( (_ / \______ | | | || | | || | | | + ,' ,-----' | \ | '--------------' || '--------------' || '--------------' | + `--{__________) \/ '----------------' '----------------' '----------------' +"# +} + +pub fn display_macos() -> &'static str{ + r#" + ,xNMM. + .OMMMMo + lMM" + .;loddo:. .olloddol;. + cKMMMMMMMMMMNWMMMMMMMMMM0: + .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. .----------------. .----------------. + XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | +;MMMMMMMMMMMMMMMMMMMMMMMM: | | ____ ____ | || | __ | || | ______ | || | ____ | || | _______ | | +:MMMMMMMMMMMMMMMMMMMMMMMM: | ||_ \ / _|| || | / \ | || | .' ___ | | || | .' `. | || | / ___ | | | +.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | \/ | | || | / /\ \ | || | / .' \_| | || | / .--. \ | || | | (__ \_| | | + kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | |\ /| | | || | / ____ \ | || | | | | || | | | | | | || | '.___`-. | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_\/_| |_ | || | _/ / \ \_ | || | \ `.___.'\ | || | \ `--' / | || | |`\____) | | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | ||_____||_____|| || ||____| |____|| || | `._____.' | || | `.____.' | || | |_______.' | | + kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | || | | || | | | + ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + "cooc*" "*coo' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_illumos() -> &'static str { + r#" +' Tw + `h||hnN + \P|||I$N + `P|||$IK, + `%wb$$IPK, + .*b|I$PPKp + `TP@|$KPPKp + `%wwI@K$PPPKw ,pKKKKm>. + "Tb@|$KPPPPKp pPPPK" + "TK@@@@K$PPPPKp,,bPPK + -wppP$$$$PPPPPPPPPPb + ,,pbP$$PPPPPPPPPP + ,,$pPPPPPPPPPPP .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. + ,pKKPPPPPPPPPL | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + -<4PPPPPPPP | | _____ | || | _____ | || | _____ | || | _____ _____ | || | ____ ____ | || | ____ | || | _______ | | + PPPPPP` | | |_ _| | || | |_ _| | || | |_ _| | || ||_ _||_ _|| || ||_ \ / _|| || | .' `. | || | / ___ | | | + /KPPPM/ | | | | | || | | | | || | | | | || | | | | | | || | | \/ | | || | / .--. \ | || | | (__ \_| | | + ,pKPPPM` | | | | | || | | | _ | || | | | _ | || | | ' ' | | || | | |\ /| | | || | | | | | | || | '.___`-. | | + ,,pKK$PPM | | _| |_ | || | _| |__/ | | || | _| |__/ | | || | \ `--' / | || | _| |_\/_| |_ | || | \ `--' / | || | |`\____) | | | + '''''qK9K | | |_____| | || | |________| | || | |________| | || | `.__.' | || ||_____||_____|| || | `.____.' | || | |_______.' | | + ,p#M",#" | | | || | | || | | || | | || | | || | | || | | | + `` ,pM` | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + '` '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' + "# +} + +pub fn display_ios() -> &'static str { + r#" + ,xNMM. + .OMMMMo + lMM" + .;loddo:. .olloddol;. + cKMMMMMMMMMMNWMMMMMMMMMM0: + .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. + XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. | +;MMMMMMMMMMMMMMMMMMMMMMMM: | | _____ | || | ____ | || | _______ | | +:MMMMMMMMMMMMMMMMMMMMMMMM: | | |_ _| | || | .' `. | || | / ___ | | | +.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | | | || | / .--. \ | || | | (__ \_| | | + kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | | | || | | | | | | || | '.___`-. | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_ | || | \ `--' / | || | |`\____) | | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | | |_____| | || | `.____.' | || | |_______.' | | + kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | | + ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' | + "cooc*" "*coo' '----------------' '----------------' '----------------' +"# +} + +pub fn display_android() -> &'static str { + r#" + -o o- + +hydNNNNdyh+ + +mMMMMMMMMMMMMm+ + `dMMm:NMMMMMMN:mMMd` + hMMMMMMMMMMMMMMMMMMh + .. yyyyyyyyyyyyyyyyyyyy .. +.mMMm`MMMMMMMMMMMMMMMMMMMM`mMMm. +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. .----------------. +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | __ | || | ____ _____ | || | ________ | || | _______ | || | ____ | || | _____ | || | ________ | | +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | / \ | || ||_ \|_ _| | || | |_ ___ `. | || | |_ __ \ | || | .' `. | || | |_ _| | || | |_ ___ `. | | +-MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM- | | / /\ \ | || | | \ | | | || | | | `. \ | || | | |__) | | || | / .--. \ | || | | | | || | | | `. \ | | + +yy+ MMMMMMMMMMMMMMMMMMMM +yy+ | | / ____ \ | || | | |\ \| | | || | | | | | | || | | __ / | || | | | | | | || | | | | || | | | | | | | + mMMMMMMMMMMMMMMMMMMm | | _/ / \ \_ | || | _| |_\ |_ | || | _| |___.' / | || | _| | \ \_ | || | \ `--' / | || | _| |_ | || | _| |___.' / | | + `/++MMMMh++hMMMM++/` | ||____| |____|| || ||_____|\____| | || | |________.' | || | |____| |___| | || | `.____.' | || | |_____| | || | |________.' | | + MMMMo oMMMM | | | || | | || | | || | | || | | || | | || | | | + MMMMo oMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + oNMm- -mMNs '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_nintendo() -> &'static str { + r#" + .-----------------. .----------------. .-----------------. .----------------. .----------------. .-----------------. .----------------. .----------------. + | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + | | ____ _____ | || | _____ | || | ____ _____ | || | _________ | || | _________ | || | ____ _____ | || | ________ | || | ____ | | + | ||_ \|_ _| | || | |_ _| | || ||_ \|_ _| | || | | _ _ | | || | |_ ___ | | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | | +⠀⠀⠀⣀⣤⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣤⡀⠀⠀⠀ | | | \ | | | || | | | | || | | \ | | | || | |_/ | | \_| | || | | |_ \_| | || | | \ | | | || | | | `. \ | || | / .--. \ | | +⠀⣠⣾⡿⠛⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠻⣿⣷⡀ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | |⠀ +⢰⣿⡏⠀⠀ ⣶⣶⣆⠀⠀⣶⣶⠀⢰⣶⡆⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣶⣶⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⡄ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | | +⣿⣿⠀⠀⠀⠀⣿⣿⢿⣧⡀⣿⣿⠀⢰⣶⡆⢰⣶⣦⠴⢶⣦⡄⠛⣿⣿⠛⢀⣤⡖⠒⣶⣄⠀⣴⣶⡦⠶⣶⣦⡀⢀⣴⡶⠶⣿⣿⠀⢠⣴⡖⠒⣦⡄⠀⠀⠸⣿⡇ | | _| |_\ |_ | || | _| |_ | || | _| |_\ |_ | || | _| |_ | || | _| |___/ | | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | | +⣿⣿⠀⠀⠀⠀⣿⣿⠀⢻⣿⣿⣿⠀⢸⣿⡇⢸⣿⡏⠀⠈⣿⣿⠀⣿⣿⠀⢾⣿⡟⠛⠛⠛⠂⣿⣿⡇⠀⢸⣿⡇⢸⣿⡇⠀⣿⣿⠀⣿⣿⠀⠀⣿⣿⠀⠀⢠⣿⡇ | ||_____|\____| | || | |_____| | || ||_____|\____| | || | |_____| | || | |_________| | || ||_____|\____| | || | |________.' | || | `.____.' | | +⠸⣿⣇⠀⠀⠀⠿⠿⠀⠀⠹⠿⠿⠀⠸⠿⠇⠸⠿⠇⠀⠠⠿⠿⠀⠿⠿⠀⠈⠻⠧⠤⠿⠟⠀⠿⠿⠇⠀⠸⠿⠇⠘⠿⣧⡤⠿⠿⠀⠘⠿⠧⠴⠿⠋⠀⢀⣾⣿⠃ | | | || | | || | | || | | || | | || | | || | | || | | | +⠀⠙⢿⣷⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣴⣿⡿⠁⠀ | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | +⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠉ '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' + "# +} +pub fn display_xbox() -> &'static str { + r#" +⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣶⣶⣶⣶⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⡀⠀⠈⠉⠛⠿⣿⣿⣿⣿⠿⠛⠉⠁⠀⢀⠀⠀⠀⠀⠀ +⠀⠀⠀⣴⣿⣿⣿⣶⣄⡀⠀⠈⠙⠋⠁⠀⢀⣠⣶⣿⣿⣿⣦⠀⠀⠀ .----------------. .----------------. .----------------. .----------------. +⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠂⠀⠀⠀⠀⠐⢿⣿⣿⣿⣿⣿⣿⣷⡀⠀ | .--------------. || .--------------. || .--------------. || .--------------. | +⠀⣾⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⢀⡀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⣷⠀ | | ____ ____ | || | ______ | || | ____ | || | ____ ____ | | +⢠⣿⣿⣿⣿⣿⡟⠁⠀⠀⢀⣴⣿⣿⣦⡀⠀⠀⠈⢻⣿⣿⣿⣿⣿⡄ | | |_ _||_ _| | || | |_ _ \ | || | .' `. | || | |_ _||_ _| | | +⢸⣿⣿⣿⣿⠏⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠹⣿⣿⣿⣿⡇ | | \ \ / / | || | | |_) | | || | / .--. \ | || | \ \ / / | | +⠘⣿⣿⣿⠏⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠹⣿⣿⣿⠃ | | > `' < | || | | __'. | || | | | | | | || | > `' < | | +⠀⢿⣿⡟⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⢻⣿⡿⠀ | | _/ /'`\ \_ | || | _| |__) | | || | \ `--' / | || | _/ /'`\ \_ | | +⠀⠈⢿⡇⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢸⡿⠁⠀ | | |____||____| | || | |_______/ | || | `.____.' | || | |____||____| | | +⠀⠀⠀⠃⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠘⠀⠀ | | | || | | || | | || | | | +⠀⠀⠀⠀⠈⠛⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠁⠀⠀⠀⠀ | '--------------' || '--------------' || '--------------' || '--------------' | +⠀⠀⠀⠀⠀⠀⠀⠈⠙⠛⠛⠿⠿⠿⠿⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' '----------------' '----------------' + "# +} + +pub fn display_playstation() -> &'static str { + r#" +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣷⣶⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠿⣿⣷⣶⣄⠀⠀⠀⠀⠀ .----------------. .----------------. +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀ | .--------------. || .--------------. | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀ | | ______ | || | _______ | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀ | | |_ __ \ | || | / ___ | | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀ | | | |__) | | || | | (__ \_| | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⠇⠀⠀⠀⠀ | | | ___/ | || | '.___`-. | | +⠀⠀⠀⠀⠀⠀⠀⣀⣤⠀⣿⣿⣿⣿⡇⠀⠈⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ | | _| |_ | || | |`\____) | | | +⠀⢀⣠⣤⣶⣾⣿⣿⡿⠀⣿⣿⣿⣿⡇⠀⢰⣶⣿⣿⣿⠿⠿⢿⣶⣦⣤⡀ | | |_____| | || | |_______.' | | +⢰⣿⣿⣿⡿⠛⠉⢀⣀⠀⣿⣿⣿⣿⡇⠀⠘⠋⠉⠀⣀⣠⣴⣾⣿⣿⣿⠇ | | | || | | | +⠈⠻⠿⣿⣿⣿⣿⣿⠿⠀⣿⣿⣿⣿⡇⠀⢠⣶⣾⣿⣿⡿⠿⠟⠋⠉⠀⠀ | '--------------' || '--------------' | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⢿⡇⠀⠸⠟⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' + "# +} + +pub fn display_redox() -> &'static str { + r#" + ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ + ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ + ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▐░▌ + ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ + ▐░█▀▀▀▀█░█▀▀ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌░▌ + ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ + ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ + "# +} + +pub fn display_fuchsia() -> &'static str { + r#" + ▄████ ▄█▄ ▄ █ ▄▄▄▄▄ ▄█ ██ + █▀ █▀ ▀▄ █ █ █ ▀▄ ██ █ █ + █▀▀ █ █ █ ▀ ██▀▀█ ▄ ▀▀▀▀▄ ██ █▄▄█ + █ █ █ █▄ ▄▀ █ █ ▀▄▄▄▄▀ ▐█ █ █ + █ █▄ ▄█ ▀███▀ █ ▐ █ + ▀ ▀▀▀ ▀ █ + ▀ + "# +} + +pub fn display_linux() -> &'static str { + r#" + .88888888:. + 88888888.88888. + .8888888888888888. + 888888888888888888 + 88' _`88'_ `88888 + 88 88 88 88 88888 + 88_88_::_88_:88888 + 88:::,::,:::::8888 + 88`:::::::::'`8888 + .88 `::::' 8:88. + 8888 `8:888. + .8888' `888888. + .8888:.. .::. ...:'8888888:. + .8888.' :' `'::`88:88888 + .8888 ' `.888:8888. + 888:8 . 888:88888 .----------------. .----------------. .-----------------. .----------------. .----------------. + .888:88 .: 888:88888: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + 8888888. :: 88:888888 | | _____ | || | _____ | || | ____ _____ | || | _____ _____ | || | ____ ____ | | + `.::.888. :: .88888888 | | |_ _| | || | |_ _| | || ||_ \|_ _| | || ||_ _||_ _|| || | |_ _||_ _| | | + .::::::.888. :: :::`8888'.:. | | | | | || | | | | || | | \ | | | || | | | | | | || | \ \ / / | | + ::::::::::.888 ' .:::::::::::: | | | | _ | || | | | | || | | |\ \| | | || | | ' ' | | || | > `' < | | + ::::::::::::.8 ' .:8::::::::::::. | | _| |__/ | | || | _| |_ | || | _| |_\ |_ | || | \ `--' / | || | _/ /'`\ \_ | | + .::::::::::::::. .:888::::::::::::: | | |________| | || | |_____| | || ||_____|\____| | || | `.__.' | || | |____||____| | | + :::::::::::::::88:.__..:88888:::::::::::' | | | || | | || | | || | | || | | | + `'.:::::::::::88888888888.88:::::::::' | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + `':::_:' -- '' -'-' `':_::::'` '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} diff --git a/src/fake.rs b/src/fake.rs index 0fe5e1a..6a28b05 100644 --- a/src/fake.rs +++ b/src/fake.rs @@ -1,75 +1,75 @@ -//! Currently used for WebAssembly unknown (non-web) only - -#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] -compile_error!("Unexpected pointer width for target platform"); - -use std::ffi::OsString; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - std::iter::once("en-US".to_string()) -} - -#[inline(always)] -pub(crate) fn username_os() -> Result { - Ok(username()?.into()) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - Ok(realname()?.into()) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[inline(always)] -pub(crate) fn distro_os() -> Result { - Ok(distro()?.into()) -} - -#[inline(always)] -pub(crate) fn username() -> Result { - Ok("anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok("Anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn devicename() -> Result { - Ok("Unknown".to_string()) -} - -#[inline(always)] -pub(crate) fn hostname() -> Result { - Ok("localhost".to_string()) -} - -#[inline(always)] -pub(crate) fn distro() -> Result { - Ok("Emulated".to_string()) -} - -#[inline(always)] -pub(crate) fn desktop_env() -> DesktopEnv { - DesktopEnv::Unknown("WebAssembly".to_string()) -} - -pub(crate) fn platform() -> Platform { - Platform::Unknown("Unknown".to_string()) -} - -pub(crate) fn arch() -> Arch { - if cfg!(target_pointer_width = "64") { - Arch::Wasm64 - } else { - Arch::Wasm32 - } -} +//! Currently used for WebAssembly unknown (non-web) only + +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("Unexpected pointer width for target platform"); + +use std::ffi::OsString; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + std::iter::once("en-US".to_string()) +} + +#[inline(always)] +pub(crate) fn username_os() -> Result { + Ok(username()?.into()) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + Ok(realname()?.into()) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[inline(always)] +pub(crate) fn distro_os() -> Result { + Ok(distro()?.into()) +} + +#[inline(always)] +pub(crate) fn username() -> Result { + Ok("anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok("Anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn devicename() -> Result { + Ok("Unknown".to_string()) +} + +#[inline(always)] +pub(crate) fn hostname() -> Result { + Ok("localhost".to_string()) +} + +#[inline(always)] +pub(crate) fn distro() -> Result { + Ok("Emulated".to_string()) +} + +#[inline(always)] +pub(crate) fn desktop_env() -> DesktopEnv { + DesktopEnv::Unknown("WebAssembly".to_string()) +} + +pub(crate) fn platform() -> Platform { + Platform::Unknown("Unknown".to_string()) +} + +pub(crate) fn arch() -> Arch { + if cfg!(target_pointer_width = "64") { + Arch::Wasm64 + } else { + Arch::Wasm32 + } +} diff --git a/src/fallible.rs b/src/fallible.rs index 5279c99..393e442 100644 --- a/src/fallible.rs +++ b/src/fallible.rs @@ -1,97 +1,97 @@ -//! Fallible versions of the whoami APIs. -//! -//! Some of the functions in the root module will return "Unknown" or -//! "localhost" on error. This might not be desirable in some situations. The -//! functions in this module all return a [`Result`]. - -use std::ffi::OsString; - -use crate::{platform, Result}; - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname()`] most notably in that spaces -/// are not allowed in the username. -#[inline(always)] -pub fn username() -> Result { - platform::username() -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname_os()`] most notably in that -/// spaces are not allowed in the username. -#[inline(always)] -pub fn username_os() -> Result { - platform::username_os() -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname() -> Result { - platform::realname() -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname_os() -> Result { - platform::realname_os() -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro() -> Result { - platform::distro() -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro_os() -> Result { - platform::distro_os() -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename() -> Result { - platform::devicename() -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename_os() -> Result { - platform::devicename_os() -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname() -> Result { - let mut hostname = platform::hostname()?; - - hostname.make_ascii_lowercase(); - - Ok(hostname) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname_os() -> Result { - Ok(hostname()?.into()) -} +//! Fallible versions of the whoami APIs. +//! +//! Some of the functions in the root module will return "Unknown" or +//! "localhost" on error. This might not be desirable in some situations. The +//! functions in this module all return a [`Result`]. + +use std::ffi::OsString; + +use crate::{platform, Result}; + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname()`] most notably in that spaces +/// are not allowed in the username. +#[inline(always)] +pub fn username() -> Result { + platform::username() +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname_os()`] most notably in that +/// spaces are not allowed in the username. +#[inline(always)] +pub fn username_os() -> Result { + platform::username_os() +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname() -> Result { + platform::realname() +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname_os() -> Result { + platform::realname_os() +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro() -> Result { + platform::distro() +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro_os() -> Result { + platform::distro_os() +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename() -> Result { + platform::devicename() +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename_os() -> Result { + platform::devicename_os() +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname() -> Result { + let mut hostname = platform::hostname()?; + + hostname.make_ascii_lowercase(); + + Ok(hostname) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname_os() -> Result { + Ok(hostname()?.into()) +} diff --git a/src/lib.rs b/src/lib.rs index 49ce2d0..4ee27ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,599 +1,600 @@ -//! Crate for getting the user's username, realname and environment. -//! -//! ## Getting Started -//! Using the whoami crate is super easy! All of the public items are simple -//! functions with no parameters that return [`String`]s or [`OsString`]s (with -//! the exception of [`desktop_env()`], [`platform()`], and [`arch()`], which -//! return enums, and [`lang()`] that returns an iterator of [`String`]s). The -//! following example shows how to use all of the functions (except those that -//! return [`OsString`]): -//! -//! ```rust -//! println!( -//! "User's Name whoami::realname(): {}", -//! whoami::realname(), -//! ); -//! println!( -//! "User's Username whoami::username(): {}", -//! whoami::username(), -//! ); -//! println!( -//! "User's Language whoami::lang(): {:?}", -//! whoami::lang().collect::>(), -//! ); -//! println!( -//! "Device's Pretty Name whoami::devicename(): {}", -//! whoami::devicename(), -//! ); -//! println!( -//! "Device's Hostname whoami::hostname(): {}", -//! whoami::hostname(), -//! ); -//! println!( -//! "Device's Platform whoami::platform(): {}", -//! whoami::platform(), -//! ); -//! println!( -//! "Device's OS Distro whoami::distro(): {}", -//! whoami::distro(), -//! ); -//! println!( -//! "Device's Desktop Env. whoami::desktop_env(): {}", -//! whoami::desktop_env(), -//! ); -//! println!( -//! "Device's CPU Arch whoami::arch(): {}", -//! whoami::arch(), -//! ); -//! ``` - -#![warn( - anonymous_parameters, - missing_copy_implementations, - missing_debug_implementations, - missing_docs, - nonstandard_style, - rust_2018_idioms, - single_use_lifetimes, - trivial_casts, - trivial_numeric_casts, - unreachable_pub, - unused_extern_crates, - unused_qualifications, - variant_size_differences, - unsafe_code -)] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg", - html_favicon_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg" -)] - -const DEFAULT_USERNAME: &str = "Unknown"; -const DEFAULT_HOSTNAME: &str = "LocalHost"; - -pub mod fallible; - -#[allow(unsafe_code)] -// Unix -#[cfg_attr( - not(any(target_os = "windows", target_arch = "wasm32")), - path = "unix.rs" -)] -// Wasm32 (Daku) - FIXME: Currently routes to fake.rs -#[cfg_attr(all(target_arch = "wasm32", target_os = "daku"), path = "fake.rs")] -// Wasm32 (Wasi) - FIXME: Currently routes to fake.rs -#[cfg_attr(all(target_arch = "wasm32", target_os = "wasi"), path = "fake.rs")] -// Wasm32 (Web) -#[cfg_attr( - all( - target_arch = "wasm32", - not(target_os = "wasi"), - not(target_os = "daku"), - feature = "web", - ), - path = "web.rs" -)] -// Wasm32 (Unknown) -#[cfg_attr( - all( - target_arch = "wasm32", - not(target_os = "wasi"), - not(target_os = "daku"), - not(feature = "web"), - ), - path = "fake.rs" -)] -// Windows -#[cfg_attr( - all(target_os = "windows", not(target_arch = "wasm32")), - path = "windows.rs" -)] -mod platform; - -use std::{ - ffi::OsString, - fmt::{self, Display, Formatter}, - io::{Error, ErrorKind}, -}; - -/// This crate's convenience type alias for [`Result`](std::result::Result)s -pub type Result = std::result::Result; - -/// Region code for a [`Language`] dialect -/// -/// Uses -#[non_exhaustive] -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum Region { - // FIXME: V2: u32::from_ne_bytes for region codes, with `\0` for unused - // FIXME: Add aliases up to 3-4 letters, but hidden - /// Any dialect - Any, - /// `US`: United States of America - #[doc(hidden)] - Us, -} - -impl Display for Region { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Self::Any => "**", - Self::Us => "US", - }) - } -} - -/// A spoken language -/// -/// Use [`ToString::to_string()`] to convert to string of two letter lowercase -/// language code followed and underscore and uppercase region code (example: -/// `en_US`). -/// -/// Uses -#[non_exhaustive] -#[derive(Clone, Eq, PartialEq, Debug)] -// #[allow(variant_size_differences)] -pub enum Language { - #[doc(hidden)] - __(Box), - /// `en`: English - #[doc(hidden)] - En(Region), - /// `es`: Spanish - #[doc(hidden)] - Es(Region), -} - -impl Language { - /// Retrieve the region code for this language dialect. - pub fn region(&self) -> Region { - match self { - Self::__(_) => Region::Any, - Self::En(region) | Self::Es(region) => *region, - } - } -} - -impl Display for Language { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::__(code) => f.write_str(code.as_str()), - Self::En(region) => { - if *region != Region::Any { - f.write_str("en_")?; - ::fmt(region, f) - } else { - f.write_str("en") - } - } - Self::Es(region) => { - if *region != Region::Any { - f.write_str("es_")?; - ::fmt(region, f) - } else { - f.write_str("es") - } - } - } - } -} - -// FIXME: V2: Move `Unknown` variants to the top of the enum. - -/// The desktop environment of a system -#[derive(Debug, PartialEq, Eq, Clone)] -#[non_exhaustive] -pub enum DesktopEnv { - /// Popular GTK-based desktop environment on Linux - Gnome, - /// One of the desktop environments for a specific version of Windows - Windows, - /// Linux desktop environment optimized for low resource requirements - Lxde, - /// Stacking window manager for X Windows on Linux - Openbox, - /// Desktop environment for Linux, BSD and Illumos - Mate, - /// Lightweight desktop enivornment for unix-like operating systems - Xfce, - /// KDE Plasma desktop enviroment - // FIXME: Rename to 'Plasma' in whoami 2.0.0 - Kde, - /// Default desktop environment on Linux Mint - Cinnamon, - /// Tiling window manager for Linux - I3, - /// Desktop environment for MacOS - Aqua, - /// Desktop environment for iOS - Ios, - /// Desktop environment for Android - Android, - /// Running as Web Assembly on a web page - WebBrowser, - /// A desktop environment for a video game console - Console, - /// Ubuntu-branded GNOME - Ubuntu, - /// Default shell for Fuchsia - Ermine, - /// Default desktop environment for Redox - Orbital, - /// Unknown desktop environment - Unknown(String), -} - -impl Display for DesktopEnv { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::Gnome => "Gnome", - Self::Windows => "Windows", - Self::Lxde => "LXDE", - Self::Openbox => "Openbox", - Self::Mate => "Mate", - Self::Xfce => "XFCE", - Self::Kde => "KDE", - Self::Cinnamon => "Cinnamon", - Self::I3 => "I3", - Self::Aqua => "Aqua", - Self::Ios => "IOS", - Self::Android => "Android", - Self::WebBrowser => "Web Browser", - Self::Console => "Console", - Self::Ubuntu => "Ubuntu", - Self::Ermine => "Ermine", - Self::Orbital => "Orbital", - Self::Unknown(a) => a, - }) - } -} - -/// The underlying platform for a system -#[allow(missing_docs)] -#[derive(Debug, PartialEq, Eq, Clone)] -#[non_exhaustive] -pub enum Platform { - Linux, - Bsd, - Windows, - // FIXME: Non-standard casing; Rename to 'Mac' rather than 'MacOs' in - // whoami 2.0.0 - MacOS, - Illumos, - Ios, - Android, - Nintendo, - Xbox, - PlayStation, - Fuchsia, - Redox, - Unknown(String), -} - -impl Display for Platform { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::Linux => "Linux", - Self::Bsd => "BSD", - Self::Windows => "Windows", - Self::MacOS => "Mac OS", - Self::Illumos => "Illumos", - Self::Ios => "iOS", - Self::Android => "Android", - Self::Nintendo => "Nintendo", - Self::Xbox => "XBox", - Self::PlayStation => "PlayStation", - Self::Fuchsia => "Fuchsia", - Self::Redox => "Redox", - Self::Unknown(a) => a, - }) - } -} - -/// The architecture of a CPU -#[non_exhaustive] -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Arch { - /// ARMv5 - ArmV5, - /// ARMv6 (Sometimes just referred to as ARM) - ArmV6, - /// ARMv7 (May or may not support Neon/Thumb) - ArmV7, - /// ARM64 (aarch64) - Arm64, - /// i386 (x86) - I386, - /// i586 (x86) - I586, - /// i686 (x86) - I686, - /// X86_64 / Amd64 - X64, - /// MIPS - Mips, - /// MIPS (LE) - MipsEl, - /// MIPS64 - Mips64, - /// MIPS64 (LE) - Mips64El, - /// PowerPC - PowerPc, - /// PowerPC64 - PowerPc64, - /// PowerPC64LE - PowerPc64Le, - /// 32-bit RISC-V - Riscv32, - /// 64-bit RISC-V - Riscv64, - /// S390x - S390x, - /// SPARC - Sparc, - /// SPARC64 - Sparc64, - /// 32-bit Web Assembly - Wasm32, - /// 64-bit Web Assembly - Wasm64, - /// Unknown Architecture - Unknown(String), -} - -impl Display for Arch { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::ArmV5 => "armv5", - Self::ArmV6 => "armv6", - Self::ArmV7 => "armv7", - Self::Arm64 => "arm64", - Self::I386 => "i386", - Self::I586 => "i586", - Self::I686 => "i686", - Self::Mips => "mips", - Self::MipsEl => "mipsel", - Self::Mips64 => "mips64", - Self::Mips64El => "mips64el", - Self::PowerPc => "powerpc", - Self::PowerPc64 => "powerpc64", - Self::PowerPc64Le => "powerpc64le", - Self::Riscv32 => "riscv32", - Self::Riscv64 => "riscv64", - Self::S390x => "s390x", - Self::Sparc => "sparc", - Self::Sparc64 => "sparc64", - Self::Wasm32 => "wasm32", - Self::Wasm64 => "wasm64", - Self::X64 => "x86_64", - Self::Unknown(arch) => arch, - }) - } -} - -/// The address width of a CPU architecture -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[non_exhaustive] -pub enum Width { - /// 32 bits - Bits32, - /// 64 bits - Bits64, -} - -impl Display for Width { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Width::Bits32 => "32 bits", - Width::Bits64 => "64 bits", - }) - } -} - -impl Arch { - /// Get the width of this architecture. - pub fn width(&self) -> Result { - match self { - Arch::ArmV5 - | Arch::ArmV6 - | Arch::ArmV7 - | Arch::I386 - | Arch::I586 - | Arch::I686 - | Arch::Mips - | Arch::MipsEl - | Arch::PowerPc - | Arch::Riscv32 - | Arch::Sparc - | Arch::Wasm32 => Ok(Width::Bits32), - Arch::Arm64 - | Arch::Mips64 - | Arch::Mips64El - | Arch::PowerPc64 - | Arch::PowerPc64Le - | Arch::Riscv64 - | Arch::S390x - | Arch::Sparc64 - | Arch::Wasm64 - | Arch::X64 => Ok(Width::Bits64), - Arch::Unknown(unknown_arch) => Err(Error::new( - ErrorKind::InvalidData, - format!( - "Tried getting width of unknown arch ({})", - unknown_arch, - ), - )), - } - } -} - -/// Get the CPU Architecture. -#[inline(always)] -pub fn arch() -> Arch { - platform::arch() -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname()`] most notably in that spaces -/// are not allowed in the username. -#[inline(always)] -pub fn username() -> String { - fallible::username().unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase()) -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname_os()`] most notably in that -/// spaces are not allowed in the username. -#[inline(always)] -pub fn username_os() -> OsString { - fallible::username_os() - .unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase().into()) -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname() -> String { - fallible::realname() - .or_else(|_| fallible::username()) - .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned()) -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname_os() -> OsString { - fallible::realname_os() - .or_else(|_| fallible::username_os()) - .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into()) -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename() -> String { - fallible::devicename() - .or_else(|_| fallible::hostname()) - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string()) -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename_os() -> OsString { - fallible::devicename_os() - .or_else(|_| fallible::hostname_os()) - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into()) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname() -> String { - fallible::hostname().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase()) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname_os() -> OsString { - fallible::hostname_os() - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase().into()) -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro() -> String { - fallible::distro().unwrap_or_else(|_| format!("Unknown {}", platform())) -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro_os() -> OsString { - fallible::distro_os() - .unwrap_or_else(|_| format!("Unknown {}", platform()).into()) -} - -/// Get the desktop environment. -/// -/// Example: "gnome" or "windows" -#[inline(always)] -pub fn desktop_env() -> DesktopEnv { - platform::desktop_env() -} - -/// Get the platform. -#[inline(always)] -pub fn platform() -> Platform { - platform::platform() -} - -/// Get the user's preferred language(s). -/// -/// Returned as iterator of two letter language codes (lowercase), optionally -/// followed by a dash (-) and a two letter region code (uppercase). The most -/// preferred language is returned first, followed by next preferred, and so on. -#[inline(always)] -#[deprecated(note = "use `langs()` instead", since = "1.5.0")] -pub fn lang() -> impl Iterator { - platform::lang() -} - -/// Get the user's preferred language(s). -/// -/// Returned as iterator of [`Language`]s wrapped in [`Result`]s. The most -/// preferred language is returned first, followed by next preferred, and so on. -/// Unrecognized languages may return an error. -#[inline(always)] -pub fn langs() -> impl Iterator> { - #[allow(deprecated)] - lang().map(|string| Ok(Language::__(Box::new(string)))) -} +//! Crate for getting the user's username, realname and environment. +//! +//! ## Getting Started +//! Using the whoami crate is super easy! All of the public items are simple +//! functions with no parameters that return [`String`]s or [`OsString`]s (with +//! the exception of [`desktop_env()`], [`platform()`], and [`arch()`], which +//! return enums, and [`lang()`] that returns an iterator of [`String`]s). The +//! following example shows how to use all of the functions (except those that +//! return [`OsString`]): +//! +//! ```rust +//! println!( +//! "User's Name whoami::realname(): {}", +//! whoami::realname(), +//! ); +//! println!( +//! "User's Username whoami::username(): {}", +//! whoami::username(), +//! ); +//! println!( +//! "User's Language whoami::lang(): {:?}", +//! whoami::lang().collect::>(), +//! ); +//! println!( +//! "Device's Pretty Name whoami::devicename(): {}", +//! whoami::devicename(), +//! ); +//! println!( +//! "Device's Hostname whoami::hostname(): {}", +//! whoami::hostname(), +//! ); +//! println!( +//! "Device's Platform whoami::platform(): {}", +//! whoami::platform(), +//! ); +//! println!( +//! "Device's OS Distro whoami::distro(): {}", +//! whoami::distro(), +//! ); +//! println!( +//! "Device's Desktop Env. whoami::desktop_env(): {}", +//! whoami::desktop_env(), +//! ); +//! println!( +//! "Device's CPU Arch whoami::arch(): {}", +//! whoami::arch(), +//! ); +//! ``` + +#![warn( + anonymous_parameters, + missing_copy_implementations, + missing_debug_implementations, + missing_docs, + nonstandard_style, + rust_2018_idioms, + single_use_lifetimes, + trivial_casts, + trivial_numeric_casts, + unreachable_pub, + unused_extern_crates, + unused_qualifications, + variant_size_differences, + unsafe_code +)] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg", + html_favicon_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg" +)] + +const DEFAULT_USERNAME: &str = "Unknown"; +const DEFAULT_HOSTNAME: &str = "LocalHost"; + +pub mod fallible; +pub mod disp; + +#[allow(unsafe_code)] +// Unix +#[cfg_attr( + not(any(target_os = "windows", target_arch = "wasm32")), + path = "unix.rs" +)] +// Wasm32 (Daku) - FIXME: Currently routes to fake.rs +#[cfg_attr(all(target_arch = "wasm32", target_os = "daku"), path = "fake.rs")] +// Wasm32 (Wasi) - FIXME: Currently routes to fake.rs +#[cfg_attr(all(target_arch = "wasm32", target_os = "wasi"), path = "fake.rs")] +// Wasm32 (Web) +#[cfg_attr( + all( + target_arch = "wasm32", + not(target_os = "wasi"), + not(target_os = "daku"), + feature = "web", + ), + path = "web.rs" +)] +// Wasm32 (Unknown) +#[cfg_attr( + all( + target_arch = "wasm32", + not(target_os = "wasi"), + not(target_os = "daku"), + not(feature = "web"), + ), + path = "fake.rs" +)] +// Windows +#[cfg_attr( + all(target_os = "windows", not(target_arch = "wasm32")), + path = "windows.rs" +)] +mod platform; + +use std::{ + ffi::OsString, + fmt::{self, Display, Formatter}, + io::{Error, ErrorKind}, +}; + +/// This crate's convenience type alias for [`Result`](std::result::Result)s +pub type Result = std::result::Result; + +/// Region code for a [`Language`] dialect +/// +/// Uses +#[non_exhaustive] +#[repr(u32)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum Region { + // FIXME: V2: u32::from_ne_bytes for region codes, with `\0` for unused + // FIXME: Add aliases up to 3-4 letters, but hidden + /// Any dialect + Any, + /// `US`: United States of America + #[doc(hidden)] + Us, +} + +impl Display for Region { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Any => "**", + Self::Us => "US", + }) + } +} + +/// A spoken language +/// +/// Use [`ToString::to_string()`] to convert to string of two letter lowercase +/// language code followed and underscore and uppercase region code (example: +/// `en_US`). +/// +/// Uses +#[non_exhaustive] +#[derive(Clone, Eq, PartialEq, Debug)] +// #[allow(variant_size_differences)] +pub enum Language { + #[doc(hidden)] + __(Box), + /// `en`: English + #[doc(hidden)] + En(Region), + /// `es`: Spanish + #[doc(hidden)] + Es(Region), +} + +impl Language { + /// Retrieve the region code for this language dialect. + pub fn region(&self) -> Region { + match self { + Self::__(_) => Region::Any, + Self::En(region) | Self::Es(region) => *region, + } + } +} + +impl Display for Language { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::__(code) => f.write_str(code.as_str()), + Self::En(region) => { + if *region != Region::Any { + f.write_str("en_")?; + ::fmt(region, f) + } else { + f.write_str("en") + } + } + Self::Es(region) => { + if *region != Region::Any { + f.write_str("es_")?; + ::fmt(region, f) + } else { + f.write_str("es") + } + } + } + } +} + +// FIXME: V2: Move `Unknown` variants to the top of the enum. + +/// The desktop environment of a system +#[derive(Debug, PartialEq, Eq, Clone)] +#[non_exhaustive] +pub enum DesktopEnv { + /// Popular GTK-based desktop environment on Linux + Gnome, + /// One of the desktop environments for a specific version of Windows + Windows, + /// Linux desktop environment optimized for low resource requirements + Lxde, + /// Stacking window manager for X Windows on Linux + Openbox, + /// Desktop environment for Linux, BSD and Illumos + Mate, + /// Lightweight desktop enivornment for unix-like operating systems + Xfce, + /// KDE Plasma desktop enviroment + // FIXME: Rename to 'Plasma' in whoami 2.0.0 + Kde, + /// Default desktop environment on Linux Mint + Cinnamon, + /// Tiling window manager for Linux + I3, + /// Desktop environment for MacOS + Aqua, + /// Desktop environment for iOS + Ios, + /// Desktop environment for Android + Android, + /// Running as Web Assembly on a web page + WebBrowser, + /// A desktop environment for a video game console + Console, + /// Ubuntu-branded GNOME + Ubuntu, + /// Default shell for Fuchsia + Ermine, + /// Default desktop environment for Redox + Orbital, + /// Unknown desktop environment + Unknown(String), +} + +impl Display for DesktopEnv { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Self::Unknown(_) = self { + f.write_str("Unknown: ")?; + } + + f.write_str(match self { + Self::Gnome => "Gnome", + Self::Windows => "Windows", + Self::Lxde => "LXDE", + Self::Openbox => "Openbox", + Self::Mate => "Mate", + Self::Xfce => "XFCE", + Self::Kde => "KDE", + Self::Cinnamon => "Cinnamon", + Self::I3 => "I3", + Self::Aqua => "Aqua", + Self::Ios => "IOS", + Self::Android => "Android", + Self::WebBrowser => "Web Browser", + Self::Console => "Console", + Self::Ubuntu => "Ubuntu", + Self::Ermine => "Ermine", + Self::Orbital => "Orbital", + Self::Unknown(a) => a, + }) + } +} + +/// The underlying platform for a system +#[allow(missing_docs)] +#[derive(Debug, PartialEq, Eq, Clone)] +#[non_exhaustive] +pub enum Platform { + Linux, + Bsd, + Windows, + // FIXME: Non-standard casing; Rename to 'Mac' rather than 'MacOs' in + // whoami 2.0.0 + MacOS, + Illumos, + Ios, + Android, + Nintendo, + Xbox, + PlayStation, + Fuchsia, + Redox, + Unknown(String), +} + +impl Display for Platform { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Self::Unknown(_) = self { + f.write_str("Unknown: ")?; + } + + f.write_str(match self { + Self::Linux => disp::display_linux(), + Self::Bsd => disp::display_bsd(), + Self::Windows => disp::display_windows(), + Self::MacOS => disp::display_macos(), + Self::Illumos => disp::display_illumos(), + Self::Ios => disp::display_ios(), + Self::Android => disp::display_android(), + Self::Nintendo => disp::display_nintendo(), + Self::Xbox => disp::display_xbox(), + Self::PlayStation => disp::display_playstation(), + Self::Fuchsia => disp::display_fuchsia(), + Self::Redox => disp::display_redox(), + Self::Unknown(a) => a, + }) + } +} + +/// The architecture of a CPU +#[non_exhaustive] +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Arch { + /// ARMv5 + ArmV5, + /// ARMv6 (Sometimes just referred to as ARM) + ArmV6, + /// ARMv7 (May or may not support Neon/Thumb) + ArmV7, + /// ARM64 (aarch64) + Arm64, + /// i386 (x86) + I386, + /// i586 (x86) + I586, + /// i686 (x86) + I686, + /// X86_64 / Amd64 + X64, + /// MIPS + Mips, + /// MIPS (LE) + MipsEl, + /// MIPS64 + Mips64, + /// MIPS64 (LE) + Mips64El, + /// PowerPC + PowerPc, + /// PowerPC64 + PowerPc64, + /// PowerPC64LE + PowerPc64Le, + /// 32-bit RISC-V + Riscv32, + /// 64-bit RISC-V + Riscv64, + /// S390x + S390x, + /// SPARC + Sparc, + /// SPARC64 + Sparc64, + /// 32-bit Web Assembly + Wasm32, + /// 64-bit Web Assembly + Wasm64, + /// Unknown Architecture + Unknown(String), +} + +impl Display for Arch { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Self::Unknown(_) = self { + f.write_str("Unknown: ")?; + } + + f.write_str(match self { + Self::ArmV5 => "armv5", + Self::ArmV6 => "armv6", + Self::ArmV7 => "armv7", + Self::Arm64 => "arm64", + Self::I386 => "i386", + Self::I586 => "i586", + Self::I686 => "i686", + Self::Mips => "mips", + Self::MipsEl => "mipsel", + Self::Mips64 => "mips64", + Self::Mips64El => "mips64el", + Self::PowerPc => "powerpc", + Self::PowerPc64 => "powerpc64", + Self::PowerPc64Le => "powerpc64le", + Self::Riscv32 => "riscv32", + Self::Riscv64 => "riscv64", + Self::S390x => "s390x", + Self::Sparc => "sparc", + Self::Sparc64 => "sparc64", + Self::Wasm32 => "wasm32", + Self::Wasm64 => "wasm64", + Self::X64 => "x86_64", + Self::Unknown(arch) => arch, + }) + } +} + +/// The address width of a CPU architecture +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[non_exhaustive] +pub enum Width { + /// 32 bits + Bits32, + /// 64 bits + Bits64, +} + +impl Display for Width { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Width::Bits32 => "32 bits", + Width::Bits64 => "64 bits", + }) + } +} + +impl Arch { + /// Get the width of this architecture. + pub fn width(&self) -> Result { + match self { + Arch::ArmV5 + | Arch::ArmV6 + | Arch::ArmV7 + | Arch::I386 + | Arch::I586 + | Arch::I686 + | Arch::Mips + | Arch::MipsEl + | Arch::PowerPc + | Arch::Riscv32 + | Arch::Sparc + | Arch::Wasm32 => Ok(Width::Bits32), + Arch::Arm64 + | Arch::Mips64 + | Arch::Mips64El + | Arch::PowerPc64 + | Arch::PowerPc64Le + | Arch::Riscv64 + | Arch::S390x + | Arch::Sparc64 + | Arch::Wasm64 + | Arch::X64 => Ok(Width::Bits64), + Arch::Unknown(unknown_arch) => Err(Error::new( + ErrorKind::InvalidData, + format!( + "Tried getting width of unknown arch ({})", + unknown_arch, + ), + )), + } + } +} + +/// Get the CPU Architecture. +#[inline(always)] +pub fn arch() -> Arch { + platform::arch() +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname()`] most notably in that spaces +/// are not allowed in the username. +#[inline(always)] +pub fn username() -> String { + fallible::username().unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase()) +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname_os()`] most notably in that +/// spaces are not allowed in the username. +#[inline(always)] +pub fn username_os() -> OsString { + fallible::username_os() + .unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase().into()) +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname() -> String { + fallible::realname() + .or_else(|_| fallible::username()) + .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned()) +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname_os() -> OsString { + fallible::realname_os() + .or_else(|_| fallible::username_os()) + .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into()) +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename() -> String { + fallible::devicename() + .or_else(|_| fallible::hostname()) + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string()) +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename_os() -> OsString { + fallible::devicename_os() + .or_else(|_| fallible::hostname_os()) + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into()) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname() -> String { + fallible::hostname().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase()) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname_os() -> OsString { + fallible::hostname_os() + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase().into()) +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro() -> String { + fallible::distro().unwrap_or_else(|_| format!("Unknown {}", platform())) +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro_os() -> OsString { + fallible::distro_os() + .unwrap_or_else(|_| format!("Unknown {}", platform()).into()) +} + +/// Get the desktop environment. +/// +/// Example: "gnome" or "windows" +#[inline(always)] +pub fn desktop_env() -> DesktopEnv { + platform::desktop_env() +} + +/// Get the platform. +#[inline(always)] +pub fn platform() -> Platform { + platform::platform() +} + +/// Get the user's preferred language(s). +/// +/// Returned as iterator of two letter language codes (lowercase), optionally +/// followed by a dash (-) and a two letter region code (uppercase). The most +/// preferred language is returned first, followed by next preferred, and so on. +#[inline(always)] +#[deprecated(note = "use `langs()` instead", since = "1.5.0")] +pub fn lang() -> impl Iterator { + platform::lang() +} + +/// Get the user's preferred language(s). +/// +/// Returned as iterator of [`Language`]s wrapped in [`Result`]s. The most +/// preferred language is returned first, followed by next preferred, and so on. +/// Unrecognized languages may return an error. +#[inline(always)] +pub fn langs() -> impl Iterator> { + #[allow(deprecated)] + lang().map(|string| Ok(Language::__(Box::new(string)))) +} diff --git a/src/unix.rs b/src/unix.rs index 3f867c7..99cdcc8 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -1,681 +1,681 @@ -use std::{ - borrow::Cow, - ffi::{c_void, CStr, OsString}, - io::{Error, ErrorKind}, - mem, - os::{ - raw::{c_char, c_int}, - unix::ffi::OsStringExt, - }, -}; -#[cfg(target_os = "macos")] -use std::{ - os::{ - raw::{c_long, c_uchar}, - unix::ffi::OsStrExt, - }, - ptr::null_mut, -}; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[repr(C)] -struct PassWd { - pw_name: *const c_void, - pw_passwd: *const c_void, - pw_uid: u32, - pw_gid: u32, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_change: isize, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_class: *const c_void, - pw_gecos: *const c_void, - pw_dir: *const c_void, - pw_shell: *const c_void, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_expire: isize, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_fields: i32, -} - -extern "system" { - fn getpwuid_r( - uid: u32, - pwd: *mut PassWd, - buf: *mut c_void, - buflen: usize, - result: *mut *mut PassWd, - ) -> i32; - fn geteuid() -> u32; - fn gethostname(name: *mut c_void, len: usize) -> i32; -} - -#[cfg(target_os = "macos")] -#[link(name = "CoreFoundation", kind = "framework")] -#[link(name = "SystemConfiguration", kind = "framework")] -extern "system" { - fn CFStringGetCString( - the_string: *mut c_void, - buffer: *mut u8, - buffer_size: c_long, - encoding: u32, - ) -> c_uchar; - fn CFStringGetLength(the_string: *mut c_void) -> c_long; - fn CFStringGetMaximumSizeForEncoding( - length: c_long, - encoding: u32, - ) -> c_long; - fn SCDynamicStoreCopyComputerName( - store: *mut c_void, - encoding: *mut u32, - ) -> *mut c_void; - fn CFRelease(cf: *const c_void); -} - -unsafe fn strlen(cs: *const c_void) -> usize { - let mut len = 0; - let mut cs: *const u8 = cs.cast(); - while *cs != 0 { - len += 1; - cs = cs.offset(1); - } - len -} - -unsafe fn strlen_gecos(cs: *const c_void) -> usize { - let mut len = 0; - let mut cs: *const u8 = cs.cast(); - while *cs != 0 && *cs != b',' { - len += 1; - cs = cs.offset(1); - } - len -} - -// Convert an OsString into a String -fn string_from_os(string: OsString) -> String { - match string.into_string() { - Ok(string) => string, - Err(string) => string.to_string_lossy().to_string(), - } -} - -fn os_from_cstring_gecos(string: *const c_void) -> Result { - if string.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - // Get a byte slice of the c string. - let slice = unsafe { - let length = strlen_gecos(string); - - if length == 0 { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - std::slice::from_raw_parts(string.cast(), length) - }; - - // Turn byte slice into Rust String. - Ok(OsString::from_vec(slice.to_vec())) -} - -fn os_from_cstring(string: *const c_void) -> Result { - if string.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - // Get a byte slice of the c string. - let slice = unsafe { - let length = strlen(string); - - if length == 0 { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - std::slice::from_raw_parts(string.cast(), length) - }; - - // Turn byte slice into Rust String. - Ok(OsString::from_vec(slice.to_vec())) -} - -#[cfg(target_os = "macos")] -fn os_from_cfstring(string: *mut c_void) -> OsString { - if string.is_null() { - return "".to_string().into(); - } - - unsafe { - let len = CFStringGetLength(string); - let capacity = - CFStringGetMaximumSizeForEncoding(len, 134_217_984 /* UTF8 */) + 1; - let mut out = Vec::with_capacity(capacity as usize); - if CFStringGetCString( - string, - out.as_mut_ptr(), - capacity, - 134_217_984, /* UTF8 */ - ) != 0 - { - out.set_len(strlen(out.as_ptr().cast())); // Remove trailing NUL byte - out.shrink_to_fit(); - CFRelease(string); - OsString::from_vec(out) - } else { - CFRelease(string); - "".to_string().into() - } - } -} - -// This function must allocate, because a slice or Cow would still -// reference `passwd` which is dropped when this function returns. -#[inline(always)] -fn getpwuid(real: bool) -> Result { - const BUF_SIZE: usize = 16_384; // size from the man page - let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit(); - let mut passwd = mem::MaybeUninit::::uninit(); - let mut _passwd = mem::MaybeUninit::<*mut PassWd>::uninit(); - - // Get PassWd `struct`. - let passwd = unsafe { - let ret = getpwuid_r( - geteuid(), - passwd.as_mut_ptr(), - buffer.as_mut_ptr() as *mut c_void, - BUF_SIZE, - _passwd.as_mut_ptr(), - ); - - if ret != 0 { - return Err(Error::last_os_error()); - } - - let _passwd = _passwd.assume_init(); - - if _passwd.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - passwd.assume_init() - }; - - // Extract names. - if real { - os_from_cstring_gecos(passwd.pw_gecos) - } else { - os_from_cstring(passwd.pw_name) - } -} - -pub(crate) fn username() -> Result { - Ok(string_from_os(username_os()?)) -} - -pub(crate) fn username_os() -> Result { - getpwuid(false) -} - -pub(crate) fn realname() -> Result { - Ok(string_from_os(realname_os()?)) -} - -pub(crate) fn realname_os() -> Result { - getpwuid(true) -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[cfg(not(any(target_os = "macos", target_os = "illumos")))] -pub(crate) fn devicename() -> Result { - let machine_info = std::fs::read("/etc/machine-info")?; - let machine_info = String::from_utf8_lossy(&machine_info); - - for i in machine_info.split('\n') { - let mut j = i.split('='); - - if j.next() == Some("PRETTY_HOSTNAME") { - if let Some(value) = j.next() { - // FIXME: Can " be escaped in pretty name? - return Ok(value.trim_matches('"').to_string()); - } - } - } - - Err(Error::new(ErrorKind::NotFound, "Missing record")) -} - -#[cfg(target_os = "macos")] -pub(crate) fn devicename() -> Result { - Ok(string_from_os(devicename_os()?)) -} - -#[cfg(target_os = "macos")] -pub(crate) fn devicename_os() -> Result { - let out = os_from_cfstring(unsafe { - SCDynamicStoreCopyComputerName(null_mut(), null_mut()) - }); - - if out.as_bytes().is_empty() { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - Ok(out) -} - -#[cfg(target_os = "illumos")] -pub(crate) fn devicename() -> Result { - let program = std::fs::read("/etc/nodename")?; - let mut nodename = String::from_utf8_lossy(&program).to_string(); - // Remove the trailing newline - let _ = nodename.pop(); - - if nodename.is_empty() { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - Ok(nodename) -} - -pub(crate) fn hostname() -> Result { - Ok(string_from_os(hostname_os()?)) -} - -fn hostname_os() -> Result { - // Maximum hostname length = 255, plus a NULL byte. - let mut string = Vec::::with_capacity(256); - - unsafe { - if gethostname(string.as_mut_ptr() as *mut c_void, 255) == -1 { - return Err(Error::last_os_error()); - } - - string.set_len(strlen(string.as_ptr() as *const c_void)); - }; - - Ok(OsString::from_vec(string)) -} - -#[cfg(target_os = "macos")] -fn distro_xml(data: String) -> Result { - let mut product_name = None; - let mut user_visible_version = None; - - if let Some(start) = data.find("") { - if let Some(end) = data.find("") { - let mut set_product_name = false; - let mut set_user_visible_version = false; - - for line in data[start + "".len()..end].lines() { - let line = line.trim(); - - if line.starts_with("") { - match line["".len()..].trim_end_matches("") { - "ProductName" => set_product_name = true, - "ProductUserVisibleVersion" => { - set_user_visible_version = true - } - "ProductVersion" => { - if user_visible_version.is_none() { - set_user_visible_version = true - } - } - _ => {} - } - } else if line.starts_with("") { - if set_product_name { - product_name = Some( - line["".len()..] - .trim_end_matches(""), - ); - set_product_name = false; - } else if set_user_visible_version { - user_visible_version = Some( - line["".len()..] - .trim_end_matches(""), - ); - set_user_visible_version = false; - } - } - } - } - } - - Ok(if let Some(product_name) = product_name { - if let Some(user_visible_version) = user_visible_version { - format!("{} {}", product_name, user_visible_version) - } else { - product_name.to_string() - } - } else { - user_visible_version - .map(|v| format!("Mac OS (Unknown) {}", v)) - .ok_or_else(|| { - Error::new(ErrorKind::InvalidData, "Parsing failed") - })? - }) -} - -#[cfg(target_os = "macos")] -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -#[cfg(target_os = "macos")] -pub(crate) fn distro() -> Result { - if let Ok(data) = std::fs::read_to_string( - "/System/Library/CoreServices/ServerVersion.plist", - ) { - distro_xml(data) - } else if let Ok(data) = std::fs::read_to_string( - "/System/Library/CoreServices/SystemVersion.plist", - ) { - distro_xml(data) - } else { - Err(Error::new(ErrorKind::NotFound, "Missing record")) - } -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn distro() -> Result { - let program = std::fs::read("/etc/os-release")?; - let distro = String::from_utf8_lossy(&program); - let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); - let mut fallback = None; - - for i in distro.split('\n') { - let mut j = i.split('='); - - match j.next().ok_or_else(err)? { - "PRETTY_NAME" => { - return Ok(j - .next() - .ok_or_else(err)? - .trim_matches('"') - .to_string()); - } - "NAME" => { - fallback = Some( - j.next().ok_or_else(err)?.trim_matches('"').to_string(), - ) - } - _ => {} - } - } - - fallback.ok_or_else(err) -} - -#[cfg(target_os = "macos")] -#[inline(always)] -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::Aqua -} - -#[cfg(not(target_os = "macos"))] -#[inline(always)] -pub(crate) fn desktop_env() -> DesktopEnv { - match std::env::var_os("DESKTOP_SESSION") - .map(|env| env.to_string_lossy().to_string()) - { - Some(env_orig) => { - let env = env_orig.to_uppercase(); - - if env.contains("GNOME") { - DesktopEnv::Gnome - } else if env.contains("LXDE") { - DesktopEnv::Lxde - } else if env.contains("OPENBOX") { - DesktopEnv::Openbox - } else if env.contains("I3") { - DesktopEnv::I3 - } else if env.contains("UBUNTU") { - DesktopEnv::Ubuntu - } else if env.contains("PLASMA5") { - DesktopEnv::Kde - } else { - DesktopEnv::Unknown(env_orig) - } - } - // TODO: Other Linux Desktop Environments - None => DesktopEnv::Unknown("Unknown".to_string()), - } -} - -#[cfg(target_os = "macos")] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::MacOS -} - -#[cfg(not(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd", - target_os = "illumos" -)))] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Linux -} - -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" -))] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Bsd -} - -#[cfg(target_os = "illumos")] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Illumos -} - -struct LangIter { - array: String, - index: Option, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if self.index? && self.array.contains('-') { - self.index = Some(false); - let mut temp = self.array.split('-').next()?.to_string(); - mem::swap(&mut temp, &mut self.array); - Some(temp) - } else { - self.index = None; - let mut temp = String::new(); - mem::swap(&mut temp, &mut self.array); - Some(temp) - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - const DEFAULT_LANG: &str = "en_US"; - - let array = std::env::var("LANG") - .unwrap_or_default() - .split('.') - .next() - .unwrap_or(DEFAULT_LANG) - .to_string(); - let array = if array == "C" { - DEFAULT_LANG.to_string() - } else { - array - }; - - LangIter { - array: array.replace('_', "-"), - index: Some(true), - } -} - -#[repr(C)] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos" -))] -struct UtsName { - #[cfg(not(target_os = "dragonfly"))] - sysname: [c_char; 256], - #[cfg(target_os = "dragonfly")] - sysname: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - nodename: [c_char; 256], - #[cfg(target_os = "dragonfly")] - nodename: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - release: [c_char; 256], - #[cfg(target_os = "dragonfly")] - release: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - version: [c_char; 256], - #[cfg(target_os = "dragonfly")] - version: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - machine: [c_char; 256], - #[cfg(target_os = "dragonfly")] - machine: [c_char; 32], -} - -#[repr(C)] -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "redox" -))] -struct UtsName { - sysname: [c_char; 65], - nodename: [c_char; 65], - release: [c_char; 65], - version: [c_char; 65], - machine: [c_char; 65], - domainname: [c_char; 65], -} - -// Buffer initialization -impl Default for UtsName { - fn default() -> Self { - unsafe { mem::zeroed() } - } -} - -extern "C" { - #[cfg(not(target_os = "freebsd"))] - fn uname(buf: *mut UtsName) -> c_int; - - #[cfg(target_os = "freebsd")] - fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; -} -#[inline] -#[cfg(target_os = "freebsd")] -unsafe extern "C" fn uname(buf: *mut UtsName) -> c_int { - __xuname(256, buf.cast()) -} - -impl Arch { - fn from_str(s: Cow<'_, str>) -> Self { - let arch_str = match s { - Cow::Borrowed(str) => str, - Cow::Owned(ref str) => str, - }; - match arch_str { - "aarch64" | "arm64" | "aarch64_be" | "armv8b" | "armv8l" => { - Arch::Arm64 - } - "armv5" => Arch::ArmV5, - "armv6" | "arm" => Arch::ArmV6, - "armv7" => Arch::ArmV7, - "i386" => Arch::I386, - "i586" => Arch::I586, - "i686" | "i686-AT386" => Arch::I686, - "mips" => Arch::Mips, - "mipsel" => Arch::MipsEl, - "mips64" => Arch::Mips64, - "mips64el" => Arch::Mips64El, - "powerpc" | "ppc" | "ppcle" => Arch::PowerPc, - "powerpc64" | "ppc64" | "ppc64le" => Arch::PowerPc64, - "powerpc64le" => Arch::PowerPc64Le, - "riscv32" => Arch::Riscv32, - "riscv64" => Arch::Riscv64, - "s390x" => Arch::S390x, - "sparc" => Arch::Sparc, - "sparc64" => Arch::Sparc64, - "wasm32" => Arch::Wasm32, - "wasm64" => Arch::Wasm64, - "x86_64" | "amd64" => Arch::X64, - _ => Arch::Unknown(arch_str.to_owned()), - } - } -} - -pub(crate) fn arch() -> Arch { - let mut buf = UtsName::default(); - let result = unsafe { uname(&mut buf) }; - if result == -1 { - return Arch::Unknown("uname(2) failed to execute".to_owned()); - } - - let arch_str = - unsafe { CStr::from_ptr(buf.machine.as_ptr()) }.to_string_lossy(); - - Arch::from_str(arch_str) -} +use std::{ + borrow::Cow, + ffi::{c_void, CStr, OsString}, + io::{Error, ErrorKind}, + mem, + os::{ + raw::{c_char, c_int}, + unix::ffi::OsStringExt, + }, +}; +#[cfg(target_os = "macos")] +use std::{ + os::{ + raw::{c_long, c_uchar}, + unix::ffi::OsStrExt, + }, + ptr::null_mut, +}; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[repr(C)] +struct PassWd { + pw_name: *const c_void, + pw_passwd: *const c_void, + pw_uid: u32, + pw_gid: u32, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_change: isize, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_class: *const c_void, + pw_gecos: *const c_void, + pw_dir: *const c_void, + pw_shell: *const c_void, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_expire: isize, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_fields: i32, +} + +extern "system" { + fn getpwuid_r( + uid: u32, + pwd: *mut PassWd, + buf: *mut c_void, + buflen: usize, + result: *mut *mut PassWd, + ) -> i32; + fn geteuid() -> u32; + fn gethostname(name: *mut c_void, len: usize) -> i32; +} + +#[cfg(target_os = "macos")] +#[link(name = "CoreFoundation", kind = "framework")] +#[link(name = "SystemConfiguration", kind = "framework")] +extern "system" { + fn CFStringGetCString( + the_string: *mut c_void, + buffer: *mut u8, + buffer_size: c_long, + encoding: u32, + ) -> c_uchar; + fn CFStringGetLength(the_string: *mut c_void) -> c_long; + fn CFStringGetMaximumSizeForEncoding( + length: c_long, + encoding: u32, + ) -> c_long; + fn SCDynamicStoreCopyComputerName( + store: *mut c_void, + encoding: *mut u32, + ) -> *mut c_void; + fn CFRelease(cf: *const c_void); +} + +unsafe fn strlen(cs: *const c_void) -> usize { + let mut len = 0; + let mut cs: *const u8 = cs.cast(); + while *cs != 0 { + len += 1; + cs = cs.offset(1); + } + len +} + +unsafe fn strlen_gecos(cs: *const c_void) -> usize { + let mut len = 0; + let mut cs: *const u8 = cs.cast(); + while *cs != 0 && *cs != b',' { + len += 1; + cs = cs.offset(1); + } + len +} + +// Convert an OsString into a String +fn string_from_os(string: OsString) -> String { + match string.into_string() { + Ok(string) => string, + Err(string) => string.to_string_lossy().to_string(), + } +} + +fn os_from_cstring_gecos(string: *const c_void) -> Result { + if string.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + // Get a byte slice of the c string. + let slice = unsafe { + let length = strlen_gecos(string); + + if length == 0 { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + std::slice::from_raw_parts(string.cast(), length) + }; + + // Turn byte slice into Rust String. + Ok(OsString::from_vec(slice.to_vec())) +} + +fn os_from_cstring(string: *const c_void) -> Result { + if string.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + // Get a byte slice of the c string. + let slice = unsafe { + let length = strlen(string); + + if length == 0 { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + std::slice::from_raw_parts(string.cast(), length) + }; + + // Turn byte slice into Rust String. + Ok(OsString::from_vec(slice.to_vec())) +} + +#[cfg(target_os = "macos")] +fn os_from_cfstring(string: *mut c_void) -> OsString { + if string.is_null() { + return "".to_string().into(); + } + + unsafe { + let len = CFStringGetLength(string); + let capacity = + CFStringGetMaximumSizeForEncoding(len, 134_217_984 /* UTF8 */) + 1; + let mut out = Vec::with_capacity(capacity as usize); + if CFStringGetCString( + string, + out.as_mut_ptr(), + capacity, + 134_217_984, /* UTF8 */ + ) != 0 + { + out.set_len(strlen(out.as_ptr().cast())); // Remove trailing NUL byte + out.shrink_to_fit(); + CFRelease(string); + OsString::from_vec(out) + } else { + CFRelease(string); + "".to_string().into() + } + } +} + +// This function must allocate, because a slice or Cow would still +// reference `passwd` which is dropped when this function returns. +#[inline(always)] +fn getpwuid(real: bool) -> Result { + const BUF_SIZE: usize = 16_384; // size from the man page + let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit(); + let mut passwd = mem::MaybeUninit::::uninit(); + let mut _passwd = mem::MaybeUninit::<*mut PassWd>::uninit(); + + // Get PassWd `struct`. + let passwd = unsafe { + let ret = getpwuid_r( + geteuid(), + passwd.as_mut_ptr(), + buffer.as_mut_ptr() as *mut c_void, + BUF_SIZE, + _passwd.as_mut_ptr(), + ); + + if ret != 0 { + return Err(Error::last_os_error()); + } + + let _passwd = _passwd.assume_init(); + + if _passwd.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + passwd.assume_init() + }; + + // Extract names. + if real { + os_from_cstring_gecos(passwd.pw_gecos) + } else { + os_from_cstring(passwd.pw_name) + } +} + +pub(crate) fn username() -> Result { + Ok(string_from_os(username_os()?)) +} + +pub(crate) fn username_os() -> Result { + getpwuid(false) +} + +pub(crate) fn realname() -> Result { + Ok(string_from_os(realname_os()?)) +} + +pub(crate) fn realname_os() -> Result { + getpwuid(true) +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[cfg(not(any(target_os = "macos", target_os = "illumos")))] +pub(crate) fn devicename() -> Result { + let machine_info = std::fs::read("/etc/machine-info")?; + let machine_info = String::from_utf8_lossy(&machine_info); + + for i in machine_info.split('\n') { + let mut j = i.split('='); + + if j.next() == Some("PRETTY_HOSTNAME") { + if let Some(value) = j.next() { + // FIXME: Can " be escaped in pretty name? + return Ok(value.trim_matches('"').to_string()); + } + } + } + + Err(Error::new(ErrorKind::NotFound, "Missing record")) +} + +#[cfg(target_os = "macos")] +pub(crate) fn devicename() -> Result { + Ok(string_from_os(devicename_os()?)) +} + +#[cfg(target_os = "macos")] +pub(crate) fn devicename_os() -> Result { + let out = os_from_cfstring(unsafe { + SCDynamicStoreCopyComputerName(null_mut(), null_mut()) + }); + + if out.as_bytes().is_empty() { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + Ok(out) +} + +#[cfg(target_os = "illumos")] +pub(crate) fn devicename() -> Result { + let program = std::fs::read("/etc/nodename")?; + let mut nodename = String::from_utf8_lossy(&program).to_string(); + // Remove the trailing newline + let _ = nodename.pop(); + + if nodename.is_empty() { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + Ok(nodename) +} + +pub(crate) fn hostname() -> Result { + Ok(string_from_os(hostname_os()?)) +} + +fn hostname_os() -> Result { + // Maximum hostname length = 255, plus a NULL byte. + let mut string = Vec::::with_capacity(256); + + unsafe { + if gethostname(string.as_mut_ptr() as *mut c_void, 255) == -1 { + return Err(Error::last_os_error()); + } + + string.set_len(strlen(string.as_ptr() as *const c_void)); + }; + + Ok(OsString::from_vec(string)) +} + +#[cfg(target_os = "macos")] +fn distro_xml(data: String) -> Result { + let mut product_name = None; + let mut user_visible_version = None; + + if let Some(start) = data.find("") { + if let Some(end) = data.find("") { + let mut set_product_name = false; + let mut set_user_visible_version = false; + + for line in data[start + "".len()..end].lines() { + let line = line.trim(); + + if line.starts_with("") { + match line["".len()..].trim_end_matches("") { + "ProductName" => set_product_name = true, + "ProductUserVisibleVersion" => { + set_user_visible_version = true + } + "ProductVersion" => { + if user_visible_version.is_none() { + set_user_visible_version = true + } + } + _ => {} + } + } else if line.starts_with("") { + if set_product_name { + product_name = Some( + line["".len()..] + .trim_end_matches(""), + ); + set_product_name = false; + } else if set_user_visible_version { + user_visible_version = Some( + line["".len()..] + .trim_end_matches(""), + ); + set_user_visible_version = false; + } + } + } + } + } + + Ok(if let Some(product_name) = product_name { + if let Some(user_visible_version) = user_visible_version { + format!("{} {}", product_name, user_visible_version) + } else { + product_name.to_string() + } + } else { + user_visible_version + .map(|v| format!("Mac OS (Unknown) {}", v)) + .ok_or_else(|| { + Error::new(ErrorKind::InvalidData, "Parsing failed") + })? + }) +} + +#[cfg(target_os = "macos")] +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +#[cfg(target_os = "macos")] +pub(crate) fn distro() -> Result { + if let Ok(data) = std::fs::read_to_string( + "/System/Library/CoreServices/ServerVersion.plist", + ) { + distro_xml(data) + } else if let Ok(data) = std::fs::read_to_string( + "/System/Library/CoreServices/SystemVersion.plist", + ) { + distro_xml(data) + } else { + Err(Error::new(ErrorKind::NotFound, "Missing record")) + } +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn distro() -> Result { + let program = std::fs::read("/etc/os-release")?; + let distro = String::from_utf8_lossy(&program); + let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); + let mut fallback = None; + + for i in distro.split('\n') { + let mut j = i.split('='); + + match j.next().ok_or_else(err)? { + "PRETTY_NAME" => { + return Ok(j + .next() + .ok_or_else(err)? + .trim_matches('"') + .to_string()); + } + "NAME" => { + fallback = Some( + j.next().ok_or_else(err)?.trim_matches('"').to_string(), + ) + } + _ => {} + } + } + + fallback.ok_or_else(err) +} + +#[cfg(target_os = "macos")] +#[inline(always)] +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::Aqua +} + +#[cfg(not(target_os = "macos"))] +#[inline(always)] +pub(crate) fn desktop_env() -> DesktopEnv { + match std::env::var_os("DESKTOP_SESSION") + .map(|env| env.to_string_lossy().to_string()) + { + Some(env_orig) => { + let env = env_orig.to_uppercase(); + + if env.contains("GNOME") { + DesktopEnv::Gnome + } else if env.contains("LXDE") { + DesktopEnv::Lxde + } else if env.contains("OPENBOX") { + DesktopEnv::Openbox + } else if env.contains("I3") { + DesktopEnv::I3 + } else if env.contains("UBUNTU") { + DesktopEnv::Ubuntu + } else if env.contains("PLASMA5") { + DesktopEnv::Kde + } else { + DesktopEnv::Unknown(env_orig) + } + } + // TODO: Other Linux Desktop Environments + None => DesktopEnv::Unknown("Unknown".to_string()), + } +} + +#[cfg(target_os = "macos")] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::MacOS +} + +#[cfg(not(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd", + target_os = "illumos" +)))] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Linux +} + +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" +))] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Bsd +} + +#[cfg(target_os = "illumos")] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Illumos +} + +struct LangIter { + array: String, + index: Option, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if self.index? && self.array.contains('-') { + self.index = Some(false); + let mut temp = self.array.split('-').next()?.to_string(); + mem::swap(&mut temp, &mut self.array); + Some(temp) + } else { + self.index = None; + let mut temp = String::new(); + mem::swap(&mut temp, &mut self.array); + Some(temp) + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + const DEFAULT_LANG: &str = "en_US"; + + let array = std::env::var("LANG") + .unwrap_or_default() + .split('.') + .next() + .unwrap_or(DEFAULT_LANG) + .to_string(); + let array = if array == "C" { + DEFAULT_LANG.to_string() + } else { + array + }; + + LangIter { + array: array.replace('_', "-"), + index: Some(true), + } +} + +#[repr(C)] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd", + target_os = "illumos" +))] +struct UtsName { + #[cfg(not(target_os = "dragonfly"))] + sysname: [c_char; 256], + #[cfg(target_os = "dragonfly")] + sysname: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + nodename: [c_char; 256], + #[cfg(target_os = "dragonfly")] + nodename: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + release: [c_char; 256], + #[cfg(target_os = "dragonfly")] + release: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + version: [c_char; 256], + #[cfg(target_os = "dragonfly")] + version: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + machine: [c_char; 256], + #[cfg(target_os = "dragonfly")] + machine: [c_char; 32], +} + +#[repr(C)] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "redox" +))] +struct UtsName { + sysname: [c_char; 65], + nodename: [c_char; 65], + release: [c_char; 65], + version: [c_char; 65], + machine: [c_char; 65], + domainname: [c_char; 65], +} + +// Buffer initialization +impl Default for UtsName { + fn default() -> Self { + unsafe { mem::zeroed() } + } +} + +extern "C" { + #[cfg(not(target_os = "freebsd"))] + fn uname(buf: *mut UtsName) -> c_int; + + #[cfg(target_os = "freebsd")] + fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; +} +#[inline] +#[cfg(target_os = "freebsd")] +unsafe extern "C" fn uname(buf: *mut UtsName) -> c_int { + __xuname(256, buf.cast()) +} + +impl Arch { + fn from_str(s: Cow<'_, str>) -> Self { + let arch_str = match s { + Cow::Borrowed(str) => str, + Cow::Owned(ref str) => str, + }; + match arch_str { + "aarch64" | "arm64" | "aarch64_be" | "armv8b" | "armv8l" => { + Arch::Arm64 + } + "armv5" => Arch::ArmV5, + "armv6" | "arm" => Arch::ArmV6, + "armv7" => Arch::ArmV7, + "i386" => Arch::I386, + "i586" => Arch::I586, + "i686" | "i686-AT386" => Arch::I686, + "mips" => Arch::Mips, + "mipsel" => Arch::MipsEl, + "mips64" => Arch::Mips64, + "mips64el" => Arch::Mips64El, + "powerpc" | "ppc" | "ppcle" => Arch::PowerPc, + "powerpc64" | "ppc64" | "ppc64le" => Arch::PowerPc64, + "powerpc64le" => Arch::PowerPc64Le, + "riscv32" => Arch::Riscv32, + "riscv64" => Arch::Riscv64, + "s390x" => Arch::S390x, + "sparc" => Arch::Sparc, + "sparc64" => Arch::Sparc64, + "wasm32" => Arch::Wasm32, + "wasm64" => Arch::Wasm64, + "x86_64" | "amd64" => Arch::X64, + _ => Arch::Unknown(arch_str.to_owned()), + } + } +} + +pub(crate) fn arch() -> Arch { + let mut buf = UtsName::default(); + let result = unsafe { uname(&mut buf) }; + if result == -1 { + return Arch::Unknown("uname(2) failed to execute".to_owned()); + } + + let arch_str = + unsafe { CStr::from_ptr(buf.machine.as_ptr()) }.to_string_lossy(); + + Arch::from_str(arch_str) +} diff --git a/src/web.rs b/src/web.rs index 04f93e8..cf1f619 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,247 +1,247 @@ -#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] -compile_error!("Unexpected pointer width for target platform"); - -use std::{ - ffi::OsString, - io::{Error, ErrorKind}, -}; - -use wasm_bindgen::JsValue; -use web_sys::window; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -// Get the user agent -fn user_agent() -> Option { - window()?.navigator().user_agent().ok() -} - -// Get the document domain -fn document_domain() -> Option { - window()?.document()?.location()?.hostname().ok() -} - -struct LangIter { - array: Vec, - index: usize, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if let Some(value) = self.array.get(self.index) { - self.index += 1; - if let Some(lang) = value.as_string() { - Some(lang) - } else { - self.next() - } - } else { - None - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - let array = if let Some(window) = window() { - window.navigator().languages().to_vec() - } else { - Vec::new() - }; - let index = 0; - - LangIter { array, index } -} - -#[inline(always)] -pub(crate) fn username_os() -> Result { - Ok(username()?.into()) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - Ok(realname()?.into()) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[inline(always)] -pub(crate) fn distro_os() -> Result { - Ok(distro()?.into()) -} - -#[inline(always)] -pub(crate) fn username() -> Result { - Ok("anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok("Anonymous".to_string()) -} - -pub(crate) fn devicename() -> Result { - let orig_string = user_agent().unwrap_or_default(); - - let start = if let Some(s) = orig_string.rfind(' ') { - s - } else { - return Ok("Unknown Browser".to_string()); - }; - - let string = orig_string - .get(start + 1..) - .unwrap_or("Unknown Browser") - .replace('/', " "); - - Ok(if let Some(s) = string.rfind("Safari") { - if let Some(s) = orig_string.rfind("Chrome") { - if let Some(e) = orig_string.get(s..).unwrap_or_default().find(' ') - { - orig_string - .get(s..) - .unwrap_or("Chrome") - .get(..e) - .unwrap_or("Chrome") - .replace('/', " ") - } else { - "Chrome".to_string() - } - } else if orig_string.contains("Linux") { - "GNOME Web".to_string() - } else { - string.get(s..).unwrap_or("Safari").replace('/', " ") - } - } else if string.contains("Edg ") { - string.replace("Edg ", "Edge ") - } else if string.contains("OPR ") { - string.replace("OPR ", "Opera ") - } else { - string - }) -} - -#[inline(always)] -pub(crate) fn hostname() -> Result { - document_domain() - .filter(|x| !x.is_empty()) - .ok_or_else(|| Error::new(ErrorKind::NotFound, "Domain missing")) -} - -pub(crate) fn distro() -> Result { - let string = - user_agent().ok_or_else(|| Error::from(ErrorKind::PermissionDenied))?; - let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); - let begin = string.find('(').ok_or_else(err)?; - let end = string.find(')').ok_or_else(err)?; - let string = &string[begin + 1..end]; - - Ok(if string.contains("Win32") || string.contains("Win64") { - let begin = if let Some(b) = string.find("NT") { - b - } else { - return Ok("Windows".to_string()); - }; - let end = if let Some(e) = string.find('.') { - e - } else { - return Ok("Windows".to_string()); - }; - let string = &string[begin + 3..end]; - - format!("Windows {}", string) - } else if string.contains("Linux") { - let string = if string.contains("X11") || string.contains("Wayland") { - let begin = if let Some(b) = string.find(';') { - b - } else { - return Ok("Unknown Linux".to_string()); - }; - &string[begin + 2..] - } else { - string - }; - - if string.starts_with("Linux") { - "Unknown Linux".to_string() - } else { - let end = if let Some(e) = string.find(';') { - e - } else { - return Ok("Unknown Linux".to_string()); - }; - string[..end].to_string() - } - } else if let Some(begin) = string.find("Mac OS X") { - if let Some(end) = string[begin..].find(';') { - string[begin..begin + end].to_string() - } else { - string[begin..].to_string().replace('_', ".") - } - } else { - // TODO: - // Platform::FreeBsd, - // Platform::Ios, - // Platform::Android, - // Platform::Nintendo, - // Platform::Xbox, - // Platform::PlayStation, - // Platform::Dive, - // Platform::Fuchsia, - // Platform::Redox - string.to_string() - }) -} - -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::WebBrowser -} - -pub(crate) fn platform() -> Platform { - let string = user_agent().unwrap_or_default(); - - let begin = if let Some(b) = string.find('(') { - b - } else { - return Platform::Unknown("Unknown".to_string()); - }; - let end = if let Some(e) = string.find(')') { - e - } else { - return Platform::Unknown("Unknown".to_string()); - }; - let string = &string[begin + 1..end]; - - if string.contains("Win32") || string.contains("Win64") { - Platform::Windows - } else if string.contains("Linux") { - Platform::Linux - } else if string.contains("Mac OS X") { - Platform::MacOS - } else { - // TODO: - // Platform::FreeBsd, - // Platform::Ios, - // Platform::Android, - // Platform::Nintendo, - // Platform::Xbox, - // Platform::PlayStation, - // Platform::Dive, - // Platform::Fuchsia, - // Platform::Redox, - Platform::Unknown(string.to_string()) - } -} - -pub(crate) fn arch() -> Arch { - if cfg!(target_pointer_width = "64") { - Arch::Wasm64 - } else { - Arch::Wasm32 - } -} +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("Unexpected pointer width for target platform"); + +use std::{ + ffi::OsString, + io::{Error, ErrorKind}, +}; + +use wasm_bindgen::JsValue; +use web_sys::window; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +// Get the user agent +fn user_agent() -> Option { + window()?.navigator().user_agent().ok() +} + +// Get the document domain +fn document_domain() -> Option { + window()?.document()?.location()?.hostname().ok() +} + +struct LangIter { + array: Vec, + index: usize, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if let Some(value) = self.array.get(self.index) { + self.index += 1; + if let Some(lang) = value.as_string() { + Some(lang) + } else { + self.next() + } + } else { + None + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + let array = if let Some(window) = window() { + window.navigator().languages().to_vec() + } else { + Vec::new() + }; + let index = 0; + + LangIter { array, index } +} + +#[inline(always)] +pub(crate) fn username_os() -> Result { + Ok(username()?.into()) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + Ok(realname()?.into()) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[inline(always)] +pub(crate) fn distro_os() -> Result { + Ok(distro()?.into()) +} + +#[inline(always)] +pub(crate) fn username() -> Result { + Ok("anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok("Anonymous".to_string()) +} + +pub(crate) fn devicename() -> Result { + let orig_string = user_agent().unwrap_or_default(); + + let start = if let Some(s) = orig_string.rfind(' ') { + s + } else { + return Ok("Unknown Browser".to_string()); + }; + + let string = orig_string + .get(start + 1..) + .unwrap_or("Unknown Browser") + .replace('/', " "); + + Ok(if let Some(s) = string.rfind("Safari") { + if let Some(s) = orig_string.rfind("Chrome") { + if let Some(e) = orig_string.get(s..).unwrap_or_default().find(' ') + { + orig_string + .get(s..) + .unwrap_or("Chrome") + .get(..e) + .unwrap_or("Chrome") + .replace('/', " ") + } else { + "Chrome".to_string() + } + } else if orig_string.contains("Linux") { + "GNOME Web".to_string() + } else { + string.get(s..).unwrap_or("Safari").replace('/', " ") + } + } else if string.contains("Edg ") { + string.replace("Edg ", "Edge ") + } else if string.contains("OPR ") { + string.replace("OPR ", "Opera ") + } else { + string + }) +} + +#[inline(always)] +pub(crate) fn hostname() -> Result { + document_domain() + .filter(|x| !x.is_empty()) + .ok_or_else(|| Error::new(ErrorKind::NotFound, "Domain missing")) +} + +pub(crate) fn distro() -> Result { + let string = + user_agent().ok_or_else(|| Error::from(ErrorKind::PermissionDenied))?; + let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); + let begin = string.find('(').ok_or_else(err)?; + let end = string.find(')').ok_or_else(err)?; + let string = &string[begin + 1..end]; + + Ok(if string.contains("Win32") || string.contains("Win64") { + let begin = if let Some(b) = string.find("NT") { + b + } else { + return Ok("Windows".to_string()); + }; + let end = if let Some(e) = string.find('.') { + e + } else { + return Ok("Windows".to_string()); + }; + let string = &string[begin + 3..end]; + + format!("Windows {}", string) + } else if string.contains("Linux") { + let string = if string.contains("X11") || string.contains("Wayland") { + let begin = if let Some(b) = string.find(';') { + b + } else { + return Ok("Unknown Linux".to_string()); + }; + &string[begin + 2..] + } else { + string + }; + + if string.starts_with("Linux") { + "Unknown Linux".to_string() + } else { + let end = if let Some(e) = string.find(';') { + e + } else { + return Ok("Unknown Linux".to_string()); + }; + string[..end].to_string() + } + } else if let Some(begin) = string.find("Mac OS X") { + if let Some(end) = string[begin..].find(';') { + string[begin..begin + end].to_string() + } else { + string[begin..].to_string().replace('_', ".") + } + } else { + // TODO: + // Platform::FreeBsd, + // Platform::Ios, + // Platform::Android, + // Platform::Nintendo, + // Platform::Xbox, + // Platform::PlayStation, + // Platform::Dive, + // Platform::Fuchsia, + // Platform::Redox + string.to_string() + }) +} + +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::WebBrowser +} + +pub(crate) fn platform() -> Platform { + let string = user_agent().unwrap_or_default(); + + let begin = if let Some(b) = string.find('(') { + b + } else { + return Platform::Unknown("Unknown".to_string()); + }; + let end = if let Some(e) = string.find(')') { + e + } else { + return Platform::Unknown("Unknown".to_string()); + }; + let string = &string[begin + 1..end]; + + if string.contains("Win32") || string.contains("Win64") { + Platform::Windows + } else if string.contains("Linux") { + Platform::Linux + } else if string.contains("Mac OS X") { + Platform::MacOS + } else { + // TODO: + // Platform::FreeBsd, + // Platform::Ios, + // Platform::Android, + // Platform::Nintendo, + // Platform::Xbox, + // Platform::PlayStation, + // Platform::Dive, + // Platform::Fuchsia, + // Platform::Redox, + Platform::Unknown(string.to_string()) + } +} + +pub(crate) fn arch() -> Arch { + if cfg!(target_pointer_width = "64") { + Arch::Wasm64 + } else { + Arch::Wasm32 + } +} diff --git a/src/windows.rs b/src/windows.rs index cb14273..a0efb6a 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,484 +1,484 @@ -use std::{ - convert::TryInto, - ffi::OsString, - io::Error, - mem::MaybeUninit, - os::{ - raw::{c_char, c_int, c_uchar, c_ulong, c_ushort, c_void}, - windows::ffi::OsStringExt, - }, - ptr, -}; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[repr(C)] -struct OsVersionInfoEx { - os_version_info_size: c_ulong, - major_version: c_ulong, - minor_version: c_ulong, - build_number: c_ulong, - platform_id: c_ulong, - sz_csd_version: [u16; 128], - service_pack_major: c_ushort, - service_pack_minor: c_ushort, - suite_mask: c_ushort, - product_type: c_uchar, - reserved: c_uchar, -} - -// Source: -// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#syntax -#[repr(C)] -struct SystemInfo { - processor_architecture: c_ushort, - reserved: c_ushort, - dw_page_size: c_ulong, - minimum_application_address: *mut c_void, - maximum_application_address: *mut c_void, - active_processor_mask: usize, - number_of_processors: c_ulong, - processor_type: c_ulong, - allocation_granularity: c_ulong, - processor_level: c_ushort, - processor_revision: c_ushort, -} - -#[allow(unused)] -#[repr(C)] -enum ExtendedNameFormat { - Unknown, // Nothing - FullyQualifiedDN, // Nothing - SamCompatible, // Hostname Followed By Username - Display, // Full Name - UniqueId, // Nothing - Canonical, // Nothing - UserPrincipal, // Nothing - CanonicalEx, // Nothing - ServicePrincipal, // Nothing - DnsDomain, // Nothing - GivenName, // Nothing - Surname, // Nothing -} - -#[allow(unused)] -#[repr(C)] -enum ComputerNameFormat { - NetBIOS, // Same as GetComputerNameW - DnsHostname, // Fancy Name - DnsDomain, // Nothing - DnsFullyQualified, // Fancy Name with, for example, .com - PhysicalNetBIOS, // Same as GetComputerNameW - PhysicalDnsHostname, // Same as GetComputerNameW - PhysicalDnsDomain, // Nothing - PhysicalDnsFullyQualified, // Fancy Name with, for example, .com - Max, -} - -const ERR_MORE_DATA: i32 = 0xEA; -const ERR_INSUFFICIENT_BUFFER: i32 = 0x7A; - -#[link(name = "secur32")] -extern "system" { - fn GetUserNameExW( - a: ExtendedNameFormat, - b: *mut c_char, - c: *mut c_ulong, - ) -> c_uchar; - fn GetUserNameW(a: *mut c_char, b: *mut c_ulong) -> c_int; - fn GetComputerNameExW( - a: ComputerNameFormat, - b: *mut c_char, - c: *mut c_ulong, - ) -> c_int; -} - -#[link(name = "kernel32")] -extern "system" { - fn GetUserPreferredUILanguages( - dw_flags: c_ulong, - pul_num_languages: *mut c_ulong, - pwsz_languages_buffer: *mut u16, - pcch_languages_buffer: *mut c_ulong, - ) -> c_int; - fn GetNativeSystemInfo(system_info: *mut SystemInfo); -} - -// Convert an OsString into a String -fn string_from_os(string: OsString) -> String { - match string.into_string() { - Ok(string) => string, - Err(string) => string.to_string_lossy().to_string(), - } -} - -pub(crate) fn username() -> Result { - Ok(string_from_os(username_os()?)) -} - -pub(crate) fn username_os() -> Result { - // Step 1. Retreive the entire length of the username - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetUserNameW(ptr::null_mut(), &mut size) == 0 - }; - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - size = name.capacity().try_into().unwrap_or(std::u32::MAX); - let orig_size = size; - let fail = - unsafe { GetUserNameW(name.as_mut_ptr().cast(), &mut size) == 0 }; - if fail { - return Err(Error::last_os_error()); - } - debug_assert_eq!(orig_size, size); - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - let terminator = name.pop(); // Remove Trailing Null - debug_assert_eq!(terminator, Some(0u16)); - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok(string_from_os(realname_os()?)) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - // Step 1. Retrieve the entire length of the username - let mut buf_size = 0; - let fail = unsafe { - GetUserNameExW( - ExtendedNameFormat::Display, - ptr::null_mut(), - &mut buf_size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_MORE_DATA) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(buf_size.try_into().unwrap_or(std::usize::MAX)); - let mut name_len = name.capacity().try_into().unwrap_or(std::u32::MAX); - let fail = unsafe { - GetUserNameExW( - ExtendedNameFormat::Display, - name.as_mut_ptr().cast(), - &mut name_len, - ) == 0 - }; - if fail { - return Err(Error::last_os_error()); - } - - assert_eq!(buf_size, name_len + 1); - - unsafe { - name.set_len(name_len.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -#[inline(always)] -pub(crate) fn devicename() -> Result { - Ok(string_from_os(devicename_os()?)) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - // Step 1. Retreive the entire length of the device name - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetComputerNameExW( - ComputerNameFormat::DnsHostname, - ptr::null_mut(), - &mut size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); - - if unsafe { - GetComputerNameExW( - ComputerNameFormat::DnsHostname, - name.as_mut_ptr().cast(), - &mut size, - ) == 0 - } { - return Err(Error::last_os_error()); - } - - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -pub(crate) fn hostname() -> Result { - Ok(string_from_os(hostname_os()?)) -} - -fn hostname_os() -> Result { - // Step 1. Retreive the entire length of the username - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetComputerNameExW( - ComputerNameFormat::NetBIOS, - ptr::null_mut(), - &mut size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); - - if unsafe { - GetComputerNameExW( - ComputerNameFormat::NetBIOS, - name.as_mut_ptr().cast(), - &mut size, - ) == 0 - } { - return Err(Error::last_os_error()); - } - - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -pub(crate) fn distro() -> Result { - // Due to MingW Limitations, we must dynamically load ntdll.dll - extern "system" { - fn LoadLibraryExW( - filename: *const u16, - hfile: *mut c_void, - dwflags: c_ulong, - ) -> *mut c_void; - fn FreeLibrary(hmodule: *mut c_void) -> i32; - fn GetProcAddress( - hmodule: *mut c_void, - procname: *const c_char, - ) -> *mut c_void; - } - - let mut path = "ntdll.dll\0".encode_utf16().collect::>(); - let path = path.as_mut_ptr(); - - let inst = unsafe { LoadLibraryExW(path, ptr::null_mut(), 0x0000_0800) }; - - if inst.is_null() { - return Err(Error::last_os_error()); - } - - let mut path = "RtlGetVersion\0".bytes().collect::>(); - let path = path.as_mut_ptr().cast(); - let func = unsafe { GetProcAddress(inst, path) }; - - if func.is_null() { - if unsafe { FreeLibrary(inst) } == 0 { - return Err(Error::last_os_error()); - } - - return Err(Error::last_os_error()); - } - - let get_version: unsafe extern "system" fn(a: *mut OsVersionInfoEx) -> u32 = - unsafe { std::mem::transmute(func) }; - - let mut version = MaybeUninit::::zeroed(); - - let version = unsafe { - (*version.as_mut_ptr()).os_version_info_size = - std::mem::size_of::() as u32; - get_version(version.as_mut_ptr()); - - if FreeLibrary(inst) == 0 { - return Err(Error::last_os_error()); - } - - version.assume_init() - }; - - let product = match version.product_type { - 1 => "Workstation", - 2 => "Domain Controller", - 3 => "Server", - _ => "Unknown", - }; - - Ok(format!( - "Windows {}.{}.{} ({})", - version.major_version, - version.minor_version, - version.build_number, - product, - )) -} - -#[inline(always)] -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::Windows -} - -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Windows -} - -struct LangIter { - array: Vec, - index: usize, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if let Some(value) = self.array.get(self.index) { - self.index += 1; - - Some(value.to_string()) - } else { - None - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - let mut num_languages = 0; - let mut buffer_size = 0; - let mut buffer; - - unsafe { - assert_ne!( - GetUserPreferredUILanguages( - 0x08, /* MUI_LANGUAGE_NAME */ - &mut num_languages, - ptr::null_mut(), // List of languages. - &mut buffer_size, - ), - 0 - ); - - buffer = Vec::with_capacity(buffer_size as usize); - - assert_ne!( - GetUserPreferredUILanguages( - 0x08, /* MUI_LANGUAGE_NAME */ - &mut num_languages, - buffer.as_mut_ptr(), // List of languages. - &mut buffer_size, - ), - 0 - ); - - buffer.set_len(buffer_size as usize); - } - - // We know it ends in two null characters. - buffer.pop(); - buffer.pop(); - - // - let array = String::from_utf16_lossy(&buffer) - .split('\0') - .map(|x| x.to_string()) - .collect(); - let index = 0; - - LangIter { array, index } -} - -pub(crate) fn arch() -> Arch { - fn proc(processor_type: c_ulong) -> Result { - Ok(match processor_type { - // PROCESSOR_INTEL_386 - 386 => Arch::I386, - // PROCESSOR_INTEL_486 - 486 => Arch::Unknown("I486".to_string()), - // PROCESSOR_INTEL_PENTIUM - 586 => Arch::I586, - // PROCESSOR_INTEL_IA64 - 2200 => Arch::Unknown("IA64".to_string()), - // PROCESSOR_AMD_X8664 - 8664 => Arch::X64, - v => return Err(v), - }) - } - - let buf: SystemInfo = unsafe { - let mut buf = MaybeUninit::uninit(); - GetNativeSystemInfo(buf.as_mut_ptr()); - buf.assume_init() - }; - - // Supported architectures, source: - // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#members - match buf.processor_architecture { - // PROCESSOR_ARCHITECTURE_INTEL - 0 => Arch::I686, - // PROCESSOR_ARCHITECTURE_ARM - 5 => Arch::ArmV6, - // PROCESSOR_ARCHITECTURE_IA64 - 6 => Arch::Unknown("IA64".to_string()), - // PROCESSOR_ARCHITECTURE_AMD64 - 9 => Arch::X64, - // PROCESSOR_ARCHITECTURE_ARM64 - 12 => Arch::Arm64, - // PROCESSOR_ARCHITECTURE_UNKNOWN - 0xFFFF => proc(buf.processor_type) - .unwrap_or_else(|e| Arch::Unknown(format!("Unknown ({})", e))), - invalid => proc(buf.processor_type).unwrap_or_else(|e| { - Arch::Unknown(format!("Invalid arch: {} ({})", invalid, e)) - }), - } -} +use std::{ + convert::TryInto, + ffi::OsString, + io::Error, + mem::MaybeUninit, + os::{ + raw::{c_char, c_int, c_uchar, c_ulong, c_ushort, c_void}, + windows::ffi::OsStringExt, + }, + ptr, +}; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[repr(C)] +struct OsVersionInfoEx { + os_version_info_size: c_ulong, + major_version: c_ulong, + minor_version: c_ulong, + build_number: c_ulong, + platform_id: c_ulong, + sz_csd_version: [u16; 128], + service_pack_major: c_ushort, + service_pack_minor: c_ushort, + suite_mask: c_ushort, + product_type: c_uchar, + reserved: c_uchar, +} + +// Source: +// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#syntax +#[repr(C)] +struct SystemInfo { + processor_architecture: c_ushort, + reserved: c_ushort, + dw_page_size: c_ulong, + minimum_application_address: *mut c_void, + maximum_application_address: *mut c_void, + active_processor_mask: usize, + number_of_processors: c_ulong, + processor_type: c_ulong, + allocation_granularity: c_ulong, + processor_level: c_ushort, + processor_revision: c_ushort, +} + +#[allow(unused)] +#[repr(C)] +enum ExtendedNameFormat { + Unknown, // Nothing + FullyQualifiedDN, // Nothing + SamCompatible, // Hostname Followed By Username + Display, // Full Name + UniqueId, // Nothing + Canonical, // Nothing + UserPrincipal, // Nothing + CanonicalEx, // Nothing + ServicePrincipal, // Nothing + DnsDomain, // Nothing + GivenName, // Nothing + Surname, // Nothing +} + +#[allow(unused)] +#[repr(C)] +enum ComputerNameFormat { + NetBIOS, // Same as GetComputerNameW + DnsHostname, // Fancy Name + DnsDomain, // Nothing + DnsFullyQualified, // Fancy Name with, for example, .com + PhysicalNetBIOS, // Same as GetComputerNameW + PhysicalDnsHostname, // Same as GetComputerNameW + PhysicalDnsDomain, // Nothing + PhysicalDnsFullyQualified, // Fancy Name with, for example, .com + Max, +} + +const ERR_MORE_DATA: i32 = 0xEA; +const ERR_INSUFFICIENT_BUFFER: i32 = 0x7A; + +#[link(name = "secur32")] +extern "system" { + fn GetUserNameExW( + a: ExtendedNameFormat, + b: *mut c_char, + c: *mut c_ulong, + ) -> c_uchar; + fn GetUserNameW(a: *mut c_char, b: *mut c_ulong) -> c_int; + fn GetComputerNameExW( + a: ComputerNameFormat, + b: *mut c_char, + c: *mut c_ulong, + ) -> c_int; +} + +#[link(name = "kernel32")] +extern "system" { + fn GetUserPreferredUILanguages( + dw_flags: c_ulong, + pul_num_languages: *mut c_ulong, + pwsz_languages_buffer: *mut u16, + pcch_languages_buffer: *mut c_ulong, + ) -> c_int; + fn GetNativeSystemInfo(system_info: *mut SystemInfo); +} + +// Convert an OsString into a String +fn string_from_os(string: OsString) -> String { + match string.into_string() { + Ok(string) => string, + Err(string) => string.to_string_lossy().to_string(), + } +} + +pub(crate) fn username() -> Result { + Ok(string_from_os(username_os()?)) +} + +pub(crate) fn username_os() -> Result { + // Step 1. Retreive the entire length of the username + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetUserNameW(ptr::null_mut(), &mut size) == 0 + }; + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + size = name.capacity().try_into().unwrap_or(std::u32::MAX); + let orig_size = size; + let fail = + unsafe { GetUserNameW(name.as_mut_ptr().cast(), &mut size) == 0 }; + if fail { + return Err(Error::last_os_error()); + } + debug_assert_eq!(orig_size, size); + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + let terminator = name.pop(); // Remove Trailing Null + debug_assert_eq!(terminator, Some(0u16)); + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok(string_from_os(realname_os()?)) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + // Step 1. Retrieve the entire length of the username + let mut buf_size = 0; + let fail = unsafe { + GetUserNameExW( + ExtendedNameFormat::Display, + ptr::null_mut(), + &mut buf_size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_MORE_DATA) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(buf_size.try_into().unwrap_or(std::usize::MAX)); + let mut name_len = name.capacity().try_into().unwrap_or(std::u32::MAX); + let fail = unsafe { + GetUserNameExW( + ExtendedNameFormat::Display, + name.as_mut_ptr().cast(), + &mut name_len, + ) == 0 + }; + if fail { + return Err(Error::last_os_error()); + } + + assert_eq!(buf_size, name_len + 1); + + unsafe { + name.set_len(name_len.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +#[inline(always)] +pub(crate) fn devicename() -> Result { + Ok(string_from_os(devicename_os()?)) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + // Step 1. Retreive the entire length of the device name + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetComputerNameExW( + ComputerNameFormat::DnsHostname, + ptr::null_mut(), + &mut size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); + + if unsafe { + GetComputerNameExW( + ComputerNameFormat::DnsHostname, + name.as_mut_ptr().cast(), + &mut size, + ) == 0 + } { + return Err(Error::last_os_error()); + } + + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +pub(crate) fn hostname() -> Result { + Ok(string_from_os(hostname_os()?)) +} + +fn hostname_os() -> Result { + // Step 1. Retreive the entire length of the username + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetComputerNameExW( + ComputerNameFormat::NetBIOS, + ptr::null_mut(), + &mut size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); + + if unsafe { + GetComputerNameExW( + ComputerNameFormat::NetBIOS, + name.as_mut_ptr().cast(), + &mut size, + ) == 0 + } { + return Err(Error::last_os_error()); + } + + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +pub(crate) fn distro() -> Result { + // Due to MingW Limitations, we must dynamically load ntdll.dll + extern "system" { + fn LoadLibraryExW( + filename: *const u16, + hfile: *mut c_void, + dwflags: c_ulong, + ) -> *mut c_void; + fn FreeLibrary(hmodule: *mut c_void) -> i32; + fn GetProcAddress( + hmodule: *mut c_void, + procname: *const c_char, + ) -> *mut c_void; + } + + let mut path = "ntdll.dll\0".encode_utf16().collect::>(); + let path = path.as_mut_ptr(); + + let inst = unsafe { LoadLibraryExW(path, ptr::null_mut(), 0x0000_0800) }; + + if inst.is_null() { + return Err(Error::last_os_error()); + } + + let mut path = "RtlGetVersion\0".bytes().collect::>(); + let path = path.as_mut_ptr().cast(); + let func = unsafe { GetProcAddress(inst, path) }; + + if func.is_null() { + if unsafe { FreeLibrary(inst) } == 0 { + return Err(Error::last_os_error()); + } + + return Err(Error::last_os_error()); + } + + let get_version: unsafe extern "system" fn(a: *mut OsVersionInfoEx) -> u32 = + unsafe { std::mem::transmute(func) }; + + let mut version = MaybeUninit::::zeroed(); + + let version = unsafe { + (*version.as_mut_ptr()).os_version_info_size = + std::mem::size_of::() as u32; + get_version(version.as_mut_ptr()); + + if FreeLibrary(inst) == 0 { + return Err(Error::last_os_error()); + } + + version.assume_init() + }; + + let product = match version.product_type { + 1 => "Workstation", + 2 => "Domain Controller", + 3 => "Server", + _ => "Unknown", + }; + + Ok(format!( + "Windows {}.{}.{} ({})", + version.major_version, + version.minor_version, + version.build_number, + product, + )) +} + +#[inline(always)] +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::Windows +} + +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Windows +} + +struct LangIter { + array: Vec, + index: usize, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if let Some(value) = self.array.get(self.index) { + self.index += 1; + + Some(value.to_string()) + } else { + None + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + let mut num_languages = 0; + let mut buffer_size = 0; + let mut buffer; + + unsafe { + assert_ne!( + GetUserPreferredUILanguages( + 0x08, /* MUI_LANGUAGE_NAME */ + &mut num_languages, + ptr::null_mut(), // List of languages. + &mut buffer_size, + ), + 0 + ); + + buffer = Vec::with_capacity(buffer_size as usize); + + assert_ne!( + GetUserPreferredUILanguages( + 0x08, /* MUI_LANGUAGE_NAME */ + &mut num_languages, + buffer.as_mut_ptr(), // List of languages. + &mut buffer_size, + ), + 0 + ); + + buffer.set_len(buffer_size as usize); + } + + // We know it ends in two null characters. + buffer.pop(); + buffer.pop(); + + // + let array = String::from_utf16_lossy(&buffer) + .split('\0') + .map(|x| x.to_string()) + .collect(); + let index = 0; + + LangIter { array, index } +} + +pub(crate) fn arch() -> Arch { + fn proc(processor_type: c_ulong) -> Result { + Ok(match processor_type { + // PROCESSOR_INTEL_386 + 386 => Arch::I386, + // PROCESSOR_INTEL_486 + 486 => Arch::Unknown("I486".to_string()), + // PROCESSOR_INTEL_PENTIUM + 586 => Arch::I586, + // PROCESSOR_INTEL_IA64 + 2200 => Arch::Unknown("IA64".to_string()), + // PROCESSOR_AMD_X8664 + 8664 => Arch::X64, + v => return Err(v), + }) + } + + let buf: SystemInfo = unsafe { + let mut buf = MaybeUninit::uninit(); + GetNativeSystemInfo(buf.as_mut_ptr()); + buf.assume_init() + }; + + // Supported architectures, source: + // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#members + match buf.processor_architecture { + // PROCESSOR_ARCHITECTURE_INTEL + 0 => Arch::I686, + // PROCESSOR_ARCHITECTURE_ARM + 5 => Arch::ArmV6, + // PROCESSOR_ARCHITECTURE_IA64 + 6 => Arch::Unknown("IA64".to_string()), + // PROCESSOR_ARCHITECTURE_AMD64 + 9 => Arch::X64, + // PROCESSOR_ARCHITECTURE_ARM64 + 12 => Arch::Arm64, + // PROCESSOR_ARCHITECTURE_UNKNOWN + 0xFFFF => proc(buf.processor_type) + .unwrap_or_else(|e| Arch::Unknown(format!("Unknown ({})", e))), + invalid => proc(buf.processor_type).unwrap_or_else(|e| { + Arch::Unknown(format!("Invalid arch: {} ({})", invalid, e)) + }), + } +} From a6cda7e226c2bbef2800415fcf852301f2ac2765 Mon Sep 17 00:00:00 2001 From: Sia Date: Mon, 22 Jan 2024 16:22:33 +0200 Subject: [PATCH 2/7] removing \r --- .github/ISSUE_TEMPLATE/bug_report.md | 76 +- .github/ISSUE_TEMPLATE/custom.md | 20 +- .github/ISSUE_TEMPLATE/feature_request.md | 40 +- .github/PULL_REQUEST_TEMPLATE.md | 6 +- .github/dependabot.yml | 16 +- .github/workflows/ci.yml | 422 +++---- .gitignore | 12 +- .rustfmt.toml | 18 +- .vs/ProjectSettings.json | 3 + .vs/slnx.sqlite | Bin 0 -> 90112 bytes CHANGELOG.md | 544 ++++---- CODE_OF_CONDUCT.md | 152 +-- CONTRIBUTING.md | 44 +- Cargo.toml | 86 +- LICENSE_APACHE | 352 +++--- LICENSE_BOOST | 46 +- LICENSE_MIT | 38 +- README.md | 186 +-- WASM.md | 96 +- examples/os-strings.rs | 84 +- examples/web/Cargo.toml | 72 +- examples/web/README.md | 30 +- examples/web/index.html | 28 +- examples/web/rust-toolchain | 4 +- examples/web/src/lib.rs | 114 +- examples/whoami-demo.rs | 84 +- res/icon.svg | 216 ++-- rust-toolchain | 4 +- src/disp.rs | 500 ++++---- src/fake.rs | 150 +-- src/fallible.rs | 194 +-- src/lib.rs | 1200 +++++++++--------- src/unix.rs | 1362 ++++++++++----------- src/web.rs | 494 ++++---- src/windows.rs | 968 +++++++-------- 35 files changed, 3832 insertions(+), 3829 deletions(-) create mode 100644 .vs/ProjectSettings.json create mode 100644 .vs/slnx.sqlite diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6867cf8..dd84ea7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,38 +1,38 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md index 3e9dad0..48d5f81 100644 --- a/.github/ISSUE_TEMPLATE/custom.md +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -1,10 +1,10 @@ ---- -name: Custom issue template -about: Describe this issue template's purpose here. -title: '' -labels: '' -assignees: '' - ---- - - +--- +name: Custom issue template +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 72718d5..bbcbbe7 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,20 +1,20 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8a09558..532d019 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,3 @@ - - - + + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 479c265..13b2d4f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,8 @@ -version: 2 -updates: -- package-ecosystem: cargo - directory: "/" - schedule: - interval: daily - time: "10:00" - open-pull-requests-limit: 10 +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + time: "10:00" + open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a461253..1f5f91a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,211 +1,211 @@ -on: [push, pull_request] - -name: tests - -jobs: - checks: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - tc: [nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - components: rustfmt, clippy - override: true - - run: cargo fmt --check - - run: cargo clippy -- -D warnings - checks-cross-compile: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [nightly] - cc: - - aarch64-linux-android - - i686-pc-windows-gnu - - i686-unknown-freebsd - - i686-unknown-linux-gnu - - wasm32-wasi - - x86_64-apple-darwin - - x86_64-unknown-redox - - x86_64-unknown-illumos - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - checks-cross-compile-ios: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [nightly] - cc: [aarch64-apple-ios] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - checks-cross-compile-wasm: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [nightly] - cc: [wasm32-unknown-unknown] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo update -p bumpalo --precise 3.4.0 - - run: cargo update -p web-sys --precise 0.3.55 - - run: cargo update -p js-sys --precise 0.3.55 - - run: cargo update -p wasm-bindgen --precise 0.2.78 - - run: cargo update -p log --precise 0.4.17 - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - - run: cargo clippy --no-default-features --target=${{ matrix.cc }} -- -D warnings - - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo clippy --target=${{ matrix.cc }} -- -D warnings - test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest] - tc: [1.40.0, stable, beta, nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - override: true - - run: cargo test --all --all-features - test-macos: - runs-on: macos-latest - strategy: - matrix: - tc: [stable, beta, nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - override: true - - run: cargo test --all --all-features --target=x86_64-apple-darwin - cross-compile: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.40.0, stable, beta, nightly] - cc: - - aarch64-linux-android - - i686-pc-windows-gnu - - i686-unknown-freebsd - - i686-unknown-linux-gnu - - wasm32-wasi - - x86_64-apple-darwin - - x86_64-unknown-redox - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-ios: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [1.40.0, stable, beta, nightly] - cc: [aarch64-apple-ios] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-m1: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [stable, beta, nightly] - cc: [aarch64-apple-darwin] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-wasm: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.40.0, stable, beta, nightly] - cc: [wasm32-unknown-unknown] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo update -p bumpalo --precise 3.4.0 - - run: cargo update -p web-sys --precise 0.3.55 - - run: cargo update -p js-sys --precise 0.3.55 - - run: cargo update -p wasm-bindgen --precise 0.2.78 - - run: cargo update -p log --precise 0.4.17 - - run: cargo update -p quote --precise 1.0.30 - - run: cargo update -p proc-macro2 --precise 1.0.63 - - run: cargo build --all-features --target=${{ matrix.cc }} - - run: cargo build --no-default-features --target=${{ matrix.cc }} - - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo build --target=${{ matrix.cc }} - cross-compile-illumos: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.65.0, stable, beta, nightly] - cc: - - x86_64-unknown-illumos - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} +on: [push, pull_request] + +name: tests + +jobs: + checks: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + tc: [nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + components: rustfmt, clippy + override: true + - run: cargo fmt --check + - run: cargo clippy -- -D warnings + checks-cross-compile: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [nightly] + cc: + - aarch64-linux-android + - i686-pc-windows-gnu + - i686-unknown-freebsd + - i686-unknown-linux-gnu + - wasm32-wasi + - x86_64-apple-darwin + - x86_64-unknown-redox + - x86_64-unknown-illumos + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + checks-cross-compile-ios: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [nightly] + cc: [aarch64-apple-ios] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + checks-cross-compile-wasm: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [nightly] + cc: [wasm32-unknown-unknown] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo update -p bumpalo --precise 3.4.0 + - run: cargo update -p web-sys --precise 0.3.55 + - run: cargo update -p js-sys --precise 0.3.55 + - run: cargo update -p wasm-bindgen --precise 0.2.78 + - run: cargo update -p log --precise 0.4.17 + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + - run: cargo clippy --no-default-features --target=${{ matrix.cc }} -- -D warnings + - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo clippy --target=${{ matrix.cc }} -- -D warnings + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + tc: [1.40.0, stable, beta, nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + override: true + - run: cargo test --all --all-features + test-macos: + runs-on: macos-latest + strategy: + matrix: + tc: [stable, beta, nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + override: true + - run: cargo test --all --all-features --target=x86_64-apple-darwin + cross-compile: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.40.0, stable, beta, nightly] + cc: + - aarch64-linux-android + - i686-pc-windows-gnu + - i686-unknown-freebsd + - i686-unknown-linux-gnu + - wasm32-wasi + - x86_64-apple-darwin + - x86_64-unknown-redox + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-ios: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [1.40.0, stable, beta, nightly] + cc: [aarch64-apple-ios] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-m1: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [stable, beta, nightly] + cc: [aarch64-apple-darwin] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-wasm: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.40.0, stable, beta, nightly] + cc: [wasm32-unknown-unknown] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo update -p bumpalo --precise 3.4.0 + - run: cargo update -p web-sys --precise 0.3.55 + - run: cargo update -p js-sys --precise 0.3.55 + - run: cargo update -p wasm-bindgen --precise 0.2.78 + - run: cargo update -p log --precise 0.4.17 + - run: cargo update -p quote --precise 1.0.30 + - run: cargo update -p proc-macro2 --precise 1.0.63 + - run: cargo build --all-features --target=${{ matrix.cc }} + - run: cargo build --no-default-features --target=${{ matrix.cc }} + - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo build --target=${{ matrix.cc }} + cross-compile-illumos: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.65.0, stable, beta, nightly] + cc: + - x86_64-unknown-illumos + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} diff --git a/.gitignore b/.gitignore index 39ca62a..7ed80a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -**/target/ -**/*.rs.bk -Cargo.lock -/ignore/ -/a.out -/**/*.swp +**/target/ +**/*.rs.bk +Cargo.lock +/ignore/ +/a.out +/**/*.swp diff --git a/.rustfmt.toml b/.rustfmt.toml index 48239b7..5e6866e 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,9 +1,9 @@ -# Don't deviate too much, just reduce columns and stricter enforcement -edition = "2021" -unstable_features = true -max_width = 80 -reorder_impl_items = true -group_imports = "StdExternalCrate" -imports_granularity = "Crate" -normalize_doc_attributes = true -wrap_comments = true +# Don't deviate too much, just reduce columns and stricter enforcement +edition = "2021" +unstable_features = true +max_width = 80 +reorder_impl_items = true +group_imports = "StdExternalCrate" +imports_granularity = "Crate" +normalize_doc_attributes = true +wrap_comments = true diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..f8b4888 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..86a29a7e566292584fa4ecb6d468f297f0c25788 GIT binary patch literal 90112 zcmeI5dyrdKdBCNWEUg~*-nG}evR8JjjqU6z_TAO{VaJKJTCG=Jt#&PGH!;q#=y7Gs z)=Fzh>qnpsYbPO)X$A%YE&T)dBOxy5dt6XoayEoz zI-PC~{ToF8W0XIjzk2HZMsMeIV*%GToSAzK=h?x%W`Ek=XPdD;Zh5TtMYF+l z%J80^S9>x&CpW4BGcLK}bEy>WYkDpo%O>0pAG4bsJg9ZzIkXXFxzTC38!x-{Arpeo!-5j1WK^OG0^ z!Vr&5CRD1)L@J@EWMf2t>BU$kJ{`-9`hr1s+h7e>xyaO7wR-i`TE1E-SAEbNY zX0)qknO41FJ=C1jmO;MP+4_?E`hu0rxJQ=AjMJ9VezvJ+oK}t6muH+-MbDWVm~qm8 zcC)#|b5t{qw7a>(yfJ@~r#0Ov+22*x$Qj$tD+@a2fA>kAySj>2NqMD`n~-N-uCgLD zTltmMB^O>ia>-e=lA`qrdm?W!JI3AmYaH=JxmjG_GEQWHXqZ(R)`fKP)I$5pBj;%s zqTEZ?NgYGi7+E5ktXW9f+C`z!L=&xJ<-exuH9OpH{q>{759P|l>eZhtY9CZ9DG!tt z^dQ}U=ZT)tHdySAvdnrmU1jBV+g-hp!g$Dzn9Ys^FAtg4k(cN54WZUr#>=)=*V}dc zw7KXSsG-zm!yATfSLeg%az;$h7Qnu|K4CIDE})g~sf21vt zw%8`MZPK^b>BPV`dRx@dET+=kVACcBDmt+_%|Xj~G| zwn$ldrQM=yGBFifNab9`wFa57EqR$nle}&)JG@T)`aUvEvO=p>shuTrTH0@m5~JFm zI`a`XBHMkjz($kSJ>O$;96F>wO+2T05$(~0<)(0PO{k$=oBE?cWc*{YQDeC8gk$}G}g#1E2;^T`U zUnCSR7Wq&(AK?ShVu;U2OCH`=5X$~gv=k|n!+fz&4n%^1Fz+b{A!JhtRgSFWi(X%; z><^X%AsXdNQJ>dW43_w4IG9H@p`7_}(9iqI!APi3E|fjtFkdPc!@;OG%126hWOyM^ zfsCJXaNxy0(_wm^zojE$K&&OiqU*1#Fu^kQXyFI@!^suA`VMF?1@UlQV0nFe~~YT zgT+X=;NeT9AmUUGdH84u4NI|9E_p%`)N`K?Whx0Fui!)GmIOW^`0{+->qq_Y`Md>h zIEtVOg9f8+oFguTVypPDDPCWzwY(!eMjh{uH-vmkD9tq%R!jJe$2;!xjr%;lfXf>? z;td}O`Umw!-H0QLPGDB@QdHJE<{t~<`~M#9+dA&&D1jFc00KY&2mk>f00e*l5C8%| z00;m9An@BqU}ukk*K5DvGHcTtoO^TO`H-!??cVs{w|c=-yxZ#ekkZ!-z%oB>;T> zKWqMkj(dgsJMLNTL)^n$g*(BGa((R2*l)0(Wk13`&aSdc>=Zk~_A>v-JjZ;L`90=5 zlVyU;Fwk8R(ueb)AV+wa=)wn^KF&1!wc`c>;E ztsk(y)w*nrTSu%m%fDK_X8Dxm1C|FYOP1r71D4+2ANPK>_mjOJ=zXAfsrPvA{$7*$ zW%HMjY48F9KmZ5;0U)sD2@K7ebO&`7Q^~j1T3MaHl8vs+^nS~^@L=H&9L^Nd>1Cae zZ+K!C`-n3Cmw)J-p_TDBP1jE@ipr&rKjAz{D<{{^MW;@R%KKB#I+L{WqG!T)z91@3 zUw?;lnpVz4BEeEsRNm*_?>s>(1Hsni)wHNwyfW;ZqLqo#L@^Qj4sYz%(1d^C{7n#nXfe0&Jx}HTTMd~v@Ul3O($|SqMLg#IuxUI z!r5r~LV@VgUwdijIIW9&q8C^4L^u2P_c`xDx;FEvR{G-ns)Z<1*FNmLn^uMc*_`+C zFj1cT-cOvzXl0-}--^sSi8Arae{$YME7t<`g$IJ7GJf$3&ZD&Q;`zqR`FT+p+coVx zLMwyktAUk^qVjInyPQ#4SqVjE=e(k|f$t6sMUb-1{QOido)MY*E`4k$OzR$4tre4R zBDRjdG%ysRb)IJO!pRAu8~gNKLqS@%aMGVEMv0Dp=kcKctrO18RxgBz?(nB}5BX_b zbnWcr<|@%0`strJeMr|ve)+O5(ku@U<()6R!|A1!7gnbmbCn*VJoxMjP7kg0lopCJ z<$j{v`^a`Ke#z%Y%nZIw$T*rMWuRXcD>o8~$J2ey2$nv{+2&yT0dzVoN%#YmS|7 z*0IOtUWrxTz1wZl4WqJ`(PPy0%T1|x?#G42rv^q%y4_eM6ln3_h}ha%t#XBy58NSU zuU1sqhYp%_`%x|Bd=+V`0$pVAfLK*Ie?cX8>^JH5qB50Yy*AdobQaG`(WKkyHt-}M z;vK^#UBAB9)NB+*C!Kob(Y-E{&W-A5tTkJFt6r}b&*dvMtR_Wv?KA22AvOAisL9#H z*h;Cb*?pTx1OXAQjGb$(R29`;Q5DZO&eq3TbxO5&kJ#MhbM^d6g)a#!b<|TlD?|&O zqJ@a1I8%^?dxlK95oAKW$v0aK^z=HW-!3t*TkLAFGIn*PianE5G`!2C^P)m!^j+<> zhOpegPoOtjr~}xM#I8BSt`$+w>npTo&!E_1VeKp`xLR+h%MIXiy{60c#)WbfIfLkZ zqk->_>@?|)p+@J?PYEn%66lvrvbp74Vs;+?

TEXCzJU?Z*^)P04I_A<@nu*5mxv z&b>QCNF`xasFm`CdJFfhU3y?UatE|@+#AczqFUujxA!4-Ix@OQwD90tUcP$|hblrj z)q~qEz={PLLX#9Y_3%jtgZhRFw1->HyW5W36Dd;3cp{xmEYBu$vdU>gv?$fY++4P; z++!6jkjus9WAW*PTy)Ta92l7_TtUAnQj-^i|Qgd|aUE7d%VqM!iWpkWHu_t4gS9zsH zTvt}^GKj^-&Z1vdJ6o$a1X(lCgU6%Sgf-{Z3P`;0Ao7OodJ*r~C5$)s%02)5B0m40 zwT@VB?#csEqvK4H{ zZBN-=v%g^9YroF$_V?KyVr;f=GH+q-X69_;wx&IApSM46`=b57>`$^kVJ>nl=I@#3 z*$0@H*aPghn4dDwa(Ql!yN6w3euw=6=Vb>uH#f){IF@;h`2^R)E-+8B6U_VBXSV#7 z4*&oGAOHk_01yBIKmZ8*<_Po|4(jR9+pHoG<83KLAja5c6oD95JE;i7SXxpMi1D*& zMIgq^PACE~PBx_o#MoFu5r_e?Nkt$A!QzTQjC@Tf0x{ebQv_m+>$oBi16%hf0x_6% zw;~V&SjQBB7__=e5r~1Rql!QbP90GMVn8aY2*e;%L=lLQr?4Ur!%ZPYAjX)2ia-o3 z1r&i8P4X)OF@)q(1Y+38s|dtUkw+1T;h}LwAclm-6oD89;uV1y`Z;VvU%r;YJ%@G~ zg8FVDo;z8?uwIGlxUGiWdNGzWii=C}n-MG)V>WkihW&afPIC}vlVURm?1sI1IUciL zDRaBo(62{vm*E`-w_bfa?qUr4^z9q&eb^c$rg9tpsNAXU#l_XJlRda*WUq6(VMMQr zkqqJH#kk1sL4#M{84KBkn{LNH9JmHm%wrJi+i{M8J%(fYjba-+v1RIbMn4v*V;DOy zDk*NUT|&~=iG;%{6qaCBXc)|04kVxegdN)}eLdyXxz z_p^)K^6g5-jz8$B|VUoH?x{su{k#sLk zEqh4nB_gn2uvYFVHjVDiud*%sSL|=G zowOaWecL{0`;z_rwsqT+))%ZlvOZ@E+umz`$o3h#+x}hqUAFD^&)MqCko^~o8GY0L zS9XK#r}l>Je)PZnrO|mm&s|_X%skGXVLr~h%0ADmGoR<~-ZX|fB+Bx0zd!=00AHX1hxW!?Z$&T^&$KY<3YV7 zk)C=hba5=qasBq@>fG|Mz4lAd8XL5ZX%SEeYlq%(Oclk}9zB$Y`z zmZv1rxjZG24(2I|bTUs>Ej@E`4<(YGG`X7+Nza!YqeRkEC3jIG=~M4nISWii$(|W3T>4^^?C6b==@KPe_=?)JilAh@p zr$o||9AlJ7dVYhaMAB0mhZ&<2`I+>r#-ZKDpr!lqeV=hyPo3ZQx$VZ?NFY9qF-mHY zpTQU*D(T6KJGLA5>*;g+zJnyQ{FKE3*0@*SKFeqKQ)P#5w;22N_&nb^ywm8`Yfki? zF3z}5ubk;S_YoVFQ+?-cM4+7OJNJ@m)F=CvJ){-mX6m(3Valfv8q>m5%cNj+$fq3dq>eC$iGse9- z<=lU#@em4kXr3l;7`<57aq>^*gX-v?GY+Gi?dJuy5gXKp|0D}_`cHZ;AOD+C&++*` ze*RzAw-qiM&_^Hu1b_e#00KY&2mk>f00e*l5C8&OmjFKhhx`AnJO0pfAOHk_01yBI zKmZ5;0U!VbfB+EK8U*0{e`}00^b!aF0U!VbfB+Bx0zd!=00AHX1hzH-IRD?;;}5+D z0zd!=00AHX1b_e#00KY&2mpbtK>*JGx5hX_FM$9M00KY&2mk>f00e*l5C8%|U~3bA z^Z%_q{?L0M00e*l5C8%|00;m9AOHk_01((31mOOEYm77W5(oeRAOHk_01yBIKmZ5; z0U!Vbwl)Fy{{Pkf00e*l5C8%|00?Xi0{H&lYBuP&5c_?$X@A<@ zXPdD;Zh5TtMYF+l%J80^S9>x&C$|O*=;g16fbki}y}W+?RHarDu4J#S6zbJUpitS?X!3B{wk%XIyf{=Ta%$*YsRGmQA=HK4v#NcwYZ5zLhUj z1#Q>0pBc%RTx=qh=+bk>Ix2GMfS4>TA-=i9iA2UVpGnTfGN)ZLiPNswLT)aZM%B(H z(m7-m`nQlu9hPdDZ`3bUN%a*?UEYW3==wS2Ww zt_Y=W6{yEUE;oa`MByd(Sk}ghMWNZO6e?BR#Wq%LHjNK<)5Te)&1hH8GOc>UdZ;<4ErWcov-KtS^#v=LagQvK8K*6!{cKauIISABFV8rw zik>q!Fyo{F?Pha_=cr~JX?Jsnd1L+}PiwkUvcIdWku$cPR~B^4|L&7KcXbu5lJZI= zHzCiwTxCUQw(={hOD?>47BQMYA8$zwM zjF)Y#uD9#>X>-vvP(!KBhBpk|uFi+i<&2o1Er5M_eZpjRTtF+|Rb}O)W}(z{XGv=P zqq3W&{zzLOZLv*i+oW%=(}{s?^tPy@Sxlw7!KO_NR!VMSTsQFU>(fSYk&Y{iG(}5m z=Qi~O(Wn64YZ)}B6HZhwe*F>^&8<@&B zTXTh`(6}U^ZIQC_O1nkZWMV3|kjlA=YYj4ETk<^(M7H~4fsH1ud%nlyICMyVns`q0BHE(~%T3|pnovW#HuXn?%5OBv z(He68!>FWt{e<4^a60wZ1X8DDoAjqgRmT}gO1YdQxn-WVn6Iv(anyLHc#$Oc|GLL@ zT-yG)?cZ&4yyEKmkE`+b6XT%8LEd3?6n?t+k2K{hJ%zwW>{x)|6UuKjP%f4!>Xj7!@s1lkUQ_Z=>nn zX3}-ex3!%U_Xh4_<@kv_ZMw~`?(<$QvH3*%UxzHUJb%3_k4IY@FR)Obf~38duXxYof;f|z~RSDMLOQ# z7EC_Z*m{Q_@cjQR4{|_*KmZ5;0U!VbfB+Bx0zd!=00AHX1a3J2xc|T9$e}?X00e*l z5C8%|00;m9AOHk_01yBIx10d{{@*P}4h;eUAOHk_01yBIKmZ5;0U!VbfB+D<f00e*l5C8%|00`W20{;VF=mUcQ literal 0 HcmV?d00001 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a92849..04841f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,272 +1,272 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog], and this project adheres to -[Semantic Versioning]. - -## [1.4.1] - 2023-06-25 -### Fixed - - License files not being included in package on crates.io - -## [1.4.0] - 2023-03-12 -### Added - - Support for Illumos - -## [1.3.0] - 2022-12-28 -### Added - - `Arch` enum listing CPU architectures - - `Width` enum listing CPU architecture address widths - - `arch()` function which returns an `Arch` type representing a CPU - architecture - - `Arch::width()` method which returns the address width of a CPU architecture - - *`web`* feature (enabled by default). Disabling this feature allows you to - use wasm32-unknown-unknown with whoami outside of the browser with a mock - implementation. - - Officially support compiling to WASI or Daku WebAssembly platforms; - functionality not supported yet. - - Convenience `Result` type alias. - -### Changed - - Modernized and cleaned up code style - -### Fixed - - Handling of `lang()` when `$LANG` environment variable on unix set to "C", - causing duplicated iterator elements `["C", "C"]`; now produces `["en-US"]`. - - WhoAmI reporting "Safari" when running in Chrome/Chromium browser - - WhoAmI reporting "Edg" when running in Edge browser (now reports "Edge") - - WhoAmI reporting "OPR" when running in Opera browser (now reports "Opera") - - WhoAmI reporting "Mozilla" when running in GNOME web browser (now reports - "GNOME Web") - -## [1.2.3] - 2022-09-12 -### Fixed - - WebAssembly target requiring older versions of dependencies - -## [1.2.2] - 2022-09-05 -### Added - - More details to the method documentation - -### Changed - - WhoAmI now has an official MSRV of Rust 1.40.0 - - `whoami::hostname()` is now normalized to lowercase - -## [1.2.1] - 2021-11-24 -### Fixed - - The Windows GNU target support being broken - -## [1.2.0] - 2021-11-06 -### Added - - Derives for `Clone`, `PartialEq` and `Eq` on `DesktopEnv` and `Platform` - -### Changed - - Lower MSRV for Windows - -## [1.1.5] - 2021-09-28 -### Fixed - - Segfault that occurs when passwd entry missing in docker - -## [1.1.4] - 2021-09-26 -### Changed - - There are no longer any known panics within the code, all possible panics - with whoami are now considered bugs. - - If any of the primary functions return an empty string, whoami should now - return "Unknown" or"unknown", or for `hostname()`, "localhost". - -### Fixed - - Panicking in situations where certain files don't exist / OS functions fail. - -## [1.1.3] - 2021-08-17 -### Fixed - - Circumstance where whoami points to invalid memory on Linux. - -## [1.1.2] - 2021-04-03 -### Fixed - - Not parsing the gecos field properly on unix systems (affects the - `realname()` and `realname_os()` functions; they will no longer return - extraneous commas on some systems). - -## [1.1.1] - 2021-03-13 -### Fixed - - Not compiling on target `x86_64-pc-windows-gnu`. - -## [1.1.0] - 2021-01-17 -### Added - - `lang()` function which returns an iterator over user's preferred language(s) - -## [1.0.3] - 2020-12-31 -### Fixed - - Link to logo in documentation. - -## [1.0.2] - 2020-12-31 -### Changed - - `distro()` on Windows now returns more detailed version. - -## [1.0.1] - 2020-12-16 -### Added - - Official support for BSD and variants - -### Fixed - - `platform()` will now return `Platform::Bsd` when running BSD. - - Misaligned address error on FreeBSD when calling `username()`. - -## [1.0.0] - 2020-11-23 -### Removed - - `Platform::Dive` and `DesktopEnv::Dive`, as that was an OS idea not a real OS - - Explicit support for `stdweb`, now built on `web-sys`/`wasm-bindgen`. - -## [0.9.0] - 2020-06-24 -### Added - - `stdweb` and `wasm-bindgen` support - - Versions of `-> String` functions that return `OsString`s: - - `devicename_os()` - - `distro_os()` - - `hostname_os()` - - `realname_os()` - - `username_os()` - -### Changed - - Renamed `DesktopEnv::Mac` to `DesktopEnv::Aqua` - - Renamed `DesktopEnv::Wasm` to `DesktopEnv::WebBrowser` - - Renamed `DesktopEnv::Redox` to `DesktopEnv::Orbital` - - Renamed `DesktopEnv::Fuchsia` to `DesktopEnv::Ermine` - - Renamed `Platform::FreeBsd` to `Platform::Bsd` - - Renamed `env()` to `desktop_env()` - - Renamed `host()` to `devicename()` - - Renamed `os()` to `distro()` - - Renamed `user()` to `realname()` - -### Fixed - - Inconsistencies on Windows - - MacOS running commands instead of using native APIs (this results in speed - improvements on MacOS) - - One of the Linux functions also using commands instead of native APIs (faster) - -### Contributors -Thanks to everyone who contributed to make this version of whoami possible! - -- [AldaronLau](https://github.com/AldaronLau) -- [Vlad-Shcherbina](https://github.com/Vlad-Shcherbina) - -## [0.8.2] - 2020-06-11 -### Changed - - Windows `host()` and `hostname()` now behave like they do on Linux and MacOS - -### Fixed - - Windows FFI Undefined Behavior because of not checking for errors - - Cross-compiling from Linux to Windows not working - -## [0.8.1] - 2020-02-22 -### Fixed - - Remove unnecessary use of `to_mut()` on `Cow`s returned from - `String::from_utf8_lossy()`. - -## [0.8.0] - 2020-02-21 -### Added - - Detection for KDE desktop environment. - -### Changed - - Unknown desktop environment may now contain lowercase characters. - -### Fixed - - No longer unwraps in any place where bad data from the OS could cause - a panic. - -## [0.7.0] - 2019-12-21 -### Removed - - `stdweb` dependency when targetting web assembly. - -### Changed - - All public enums now have the attribute `#[non_exhaustive]` and derive - `Debug`. - -### Fixed - - Some out-of-date documentation - -## [0.6.0] - 2019-10-25 -### Added - - Web Assembly support. - -### Removed - - `Platform::Web` variant of enum, use `env()` if you need to. - -### Changed - - `platform()` is no longer a const fn (needed for wasm platform - detection). - -## [0.5.3] - 2019-07-18 -### Changed - - Now uses a more modern Rust coding style (replace `::std::` with `std::`). - - Now uses a more modern Rust coding style with `mem::MaybeUninit`. - - `impl Display` for desktop environment now uses proper capitalization. - - Don't depend on `libc` anymore. -### Fixed - - Fancy Names not working on Windows - - `user()` now uses Windows Display Name on Windows rather than the username. - - `host()` now uses Windows Name DNS Fully Qualified rather than the hostname. - -## [0.5.2] - 2019-05-12 -### Fixed - - Fixed more broken links! - -## [0.5.1] - 2019-05-12 -### Fixed - - Clippy lint warning: change `expect(&format!("…"))` to `expect("…")` for optimization in 2 cases. - - Fixed broken links - -## [0.5.0] - 2019-03-17 -### Added - - `Platform` enum with corresponding `platform()` function. - - `Dive`, `Fuchsia`, and `Redox` to `DesktopEnv` enum. -### Changed - - Started using `const fn` for some functions. - -## [0.4.1] - 2019-01-12 -### Fixed - - Fixed README errors. - -## [0.4.0] - 2019-01-12 -### Added - - MacOS support. -### Changed - - `env` on Ubuntu now returns DesktopEnv::Ubuntu instead of DesktopEnv::Other("UBUNTU") - - Split off the binary into `whome` (who me?) crate - -## [0.3.0] - 2019-01-04 -### Added - - Added more fallbacks. -### Changed - - Rename realname -> user - - Rename computer -> host -### Fixed - - Fix typo for uknown -> unknown. - -## [0.2.4] - 2018-12-04 -### Fixed - - Works now on platforms that use u8 instead of i8 for chars (like ARM). - -## [0.2.3] - 2018-11-26 -### Fixed - - Trailing newline on Windows. - -## [0.2.2] - 2018-06-02 -### Fixed - - Typo in markdown. - -## [0.2.1] - 2018-06-02 -### Fixed - - Undefined behavior on Linux. - -## [0.2.0] - 2017-12-28 -### Added - - Windows support. - -## [0.1.1] - 2017-08-04 -### Fixed - - Something in the markdown. - -## [0.1.0] - 2017-08-04 -### Added - - Published to crates.io. - -[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ -[Semantic Versioning]: https://github.com/AldaronLau/semver/ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog], and this project adheres to +[Semantic Versioning]. + +## [1.4.1] - 2023-06-25 +### Fixed + - License files not being included in package on crates.io + +## [1.4.0] - 2023-03-12 +### Added + - Support for Illumos + +## [1.3.0] - 2022-12-28 +### Added + - `Arch` enum listing CPU architectures + - `Width` enum listing CPU architecture address widths + - `arch()` function which returns an `Arch` type representing a CPU + architecture + - `Arch::width()` method which returns the address width of a CPU architecture + - *`web`* feature (enabled by default). Disabling this feature allows you to + use wasm32-unknown-unknown with whoami outside of the browser with a mock + implementation. + - Officially support compiling to WASI or Daku WebAssembly platforms; + functionality not supported yet. + - Convenience `Result` type alias. + +### Changed + - Modernized and cleaned up code style + +### Fixed + - Handling of `lang()` when `$LANG` environment variable on unix set to "C", + causing duplicated iterator elements `["C", "C"]`; now produces `["en-US"]`. + - WhoAmI reporting "Safari" when running in Chrome/Chromium browser + - WhoAmI reporting "Edg" when running in Edge browser (now reports "Edge") + - WhoAmI reporting "OPR" when running in Opera browser (now reports "Opera") + - WhoAmI reporting "Mozilla" when running in GNOME web browser (now reports + "GNOME Web") + +## [1.2.3] - 2022-09-12 +### Fixed + - WebAssembly target requiring older versions of dependencies + +## [1.2.2] - 2022-09-05 +### Added + - More details to the method documentation + +### Changed + - WhoAmI now has an official MSRV of Rust 1.40.0 + - `whoami::hostname()` is now normalized to lowercase + +## [1.2.1] - 2021-11-24 +### Fixed + - The Windows GNU target support being broken + +## [1.2.0] - 2021-11-06 +### Added + - Derives for `Clone`, `PartialEq` and `Eq` on `DesktopEnv` and `Platform` + +### Changed + - Lower MSRV for Windows + +## [1.1.5] - 2021-09-28 +### Fixed + - Segfault that occurs when passwd entry missing in docker + +## [1.1.4] - 2021-09-26 +### Changed + - There are no longer any known panics within the code, all possible panics + with whoami are now considered bugs. + - If any of the primary functions return an empty string, whoami should now + return "Unknown" or"unknown", or for `hostname()`, "localhost". + +### Fixed + - Panicking in situations where certain files don't exist / OS functions fail. + +## [1.1.3] - 2021-08-17 +### Fixed + - Circumstance where whoami points to invalid memory on Linux. + +## [1.1.2] - 2021-04-03 +### Fixed + - Not parsing the gecos field properly on unix systems (affects the + `realname()` and `realname_os()` functions; they will no longer return + extraneous commas on some systems). + +## [1.1.1] - 2021-03-13 +### Fixed + - Not compiling on target `x86_64-pc-windows-gnu`. + +## [1.1.0] - 2021-01-17 +### Added + - `lang()` function which returns an iterator over user's preferred language(s) + +## [1.0.3] - 2020-12-31 +### Fixed + - Link to logo in documentation. + +## [1.0.2] - 2020-12-31 +### Changed + - `distro()` on Windows now returns more detailed version. + +## [1.0.1] - 2020-12-16 +### Added + - Official support for BSD and variants + +### Fixed + - `platform()` will now return `Platform::Bsd` when running BSD. + - Misaligned address error on FreeBSD when calling `username()`. + +## [1.0.0] - 2020-11-23 +### Removed + - `Platform::Dive` and `DesktopEnv::Dive`, as that was an OS idea not a real OS + - Explicit support for `stdweb`, now built on `web-sys`/`wasm-bindgen`. + +## [0.9.0] - 2020-06-24 +### Added + - `stdweb` and `wasm-bindgen` support + - Versions of `-> String` functions that return `OsString`s: + - `devicename_os()` + - `distro_os()` + - `hostname_os()` + - `realname_os()` + - `username_os()` + +### Changed + - Renamed `DesktopEnv::Mac` to `DesktopEnv::Aqua` + - Renamed `DesktopEnv::Wasm` to `DesktopEnv::WebBrowser` + - Renamed `DesktopEnv::Redox` to `DesktopEnv::Orbital` + - Renamed `DesktopEnv::Fuchsia` to `DesktopEnv::Ermine` + - Renamed `Platform::FreeBsd` to `Platform::Bsd` + - Renamed `env()` to `desktop_env()` + - Renamed `host()` to `devicename()` + - Renamed `os()` to `distro()` + - Renamed `user()` to `realname()` + +### Fixed + - Inconsistencies on Windows + - MacOS running commands instead of using native APIs (this results in speed + improvements on MacOS) + - One of the Linux functions also using commands instead of native APIs (faster) + +### Contributors +Thanks to everyone who contributed to make this version of whoami possible! + +- [AldaronLau](https://github.com/AldaronLau) +- [Vlad-Shcherbina](https://github.com/Vlad-Shcherbina) + +## [0.8.2] - 2020-06-11 +### Changed + - Windows `host()` and `hostname()` now behave like they do on Linux and MacOS + +### Fixed + - Windows FFI Undefined Behavior because of not checking for errors + - Cross-compiling from Linux to Windows not working + +## [0.8.1] - 2020-02-22 +### Fixed + - Remove unnecessary use of `to_mut()` on `Cow`s returned from + `String::from_utf8_lossy()`. + +## [0.8.0] - 2020-02-21 +### Added + - Detection for KDE desktop environment. + +### Changed + - Unknown desktop environment may now contain lowercase characters. + +### Fixed + - No longer unwraps in any place where bad data from the OS could cause + a panic. + +## [0.7.0] - 2019-12-21 +### Removed + - `stdweb` dependency when targetting web assembly. + +### Changed + - All public enums now have the attribute `#[non_exhaustive]` and derive + `Debug`. + +### Fixed + - Some out-of-date documentation + +## [0.6.0] - 2019-10-25 +### Added + - Web Assembly support. + +### Removed + - `Platform::Web` variant of enum, use `env()` if you need to. + +### Changed + - `platform()` is no longer a const fn (needed for wasm platform + detection). + +## [0.5.3] - 2019-07-18 +### Changed + - Now uses a more modern Rust coding style (replace `::std::` with `std::`). + - Now uses a more modern Rust coding style with `mem::MaybeUninit`. + - `impl Display` for desktop environment now uses proper capitalization. + - Don't depend on `libc` anymore. +### Fixed + - Fancy Names not working on Windows + - `user()` now uses Windows Display Name on Windows rather than the username. + - `host()` now uses Windows Name DNS Fully Qualified rather than the hostname. + +## [0.5.2] - 2019-05-12 +### Fixed + - Fixed more broken links! + +## [0.5.1] - 2019-05-12 +### Fixed + - Clippy lint warning: change `expect(&format!("…"))` to `expect("…")` for optimization in 2 cases. + - Fixed broken links + +## [0.5.0] - 2019-03-17 +### Added + - `Platform` enum with corresponding `platform()` function. + - `Dive`, `Fuchsia`, and `Redox` to `DesktopEnv` enum. +### Changed + - Started using `const fn` for some functions. + +## [0.4.1] - 2019-01-12 +### Fixed + - Fixed README errors. + +## [0.4.0] - 2019-01-12 +### Added + - MacOS support. +### Changed + - `env` on Ubuntu now returns DesktopEnv::Ubuntu instead of DesktopEnv::Other("UBUNTU") + - Split off the binary into `whome` (who me?) crate + +## [0.3.0] - 2019-01-04 +### Added + - Added more fallbacks. +### Changed + - Rename realname -> user + - Rename computer -> host +### Fixed + - Fix typo for uknown -> unknown. + +## [0.2.4] - 2018-12-04 +### Fixed + - Works now on platforms that use u8 instead of i8 for chars (like ARM). + +## [0.2.3] - 2018-11-26 +### Fixed + - Trailing newline on Windows. + +## [0.2.2] - 2018-06-02 +### Fixed + - Typo in markdown. + +## [0.2.1] - 2018-06-02 +### Fixed + - Undefined behavior on Linux. + +## [0.2.0] - 2017-12-28 +### Added + - Windows support. + +## [0.1.1] - 2017-08-04 +### Fixed + - Something in the markdown. + +## [0.1.0] - 2017-08-04 +### Added + - Published to crates.io. + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ +[Semantic Versioning]: https://github.com/AldaronLau/semver/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index efdbb5b..b19a756 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,76 +1,76 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at aldaronlau@gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at aldaronlau@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 635bae5..8fc20ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,22 @@ -# Contributing -Anyone is welcome to contribute! You can [open an issue], -[Post to GitHub Discussions] or [send me an email] about anything related to -this project. You may also [open a PR]. I don't require PRs to be formatted in -a specific manner, since I'll run it through rustfmt after the merge anyway. If -you're going to work on a PR, it would be preferred to let me know ahead of time -(unless it's a quick fix), and open a draft PR if it's a large one. Then I'll -assign the issue to you. Otherwise, I can't guarantee I won't duplicate your -work. If I can't contact you within a week, I may unassign you and finish your -work (opening a Draft PR on this repository puts your code under this crate's -license). - -If you open a bug report, you can usually expect it to be fixed within a week. -If you open a feature request it may stay open indefinitely, until I need it -too. I mark feature requests as "enhancements" on GitHub issues. - -Happy coding! - -[open an issue]: https://github.com/ardaku/whoami/issues -[send me an email]: mailto:aldaronlau@gmail.com -[open a PR]: https://github.com/ardaku/whoami/pulls -[Post to GitHub Discussions]: https://github.com/ardaku/whoami/discussions +# Contributing +Anyone is welcome to contribute! You can [open an issue], +[Post to GitHub Discussions] or [send me an email] about anything related to +this project. You may also [open a PR]. I don't require PRs to be formatted in +a specific manner, since I'll run it through rustfmt after the merge anyway. If +you're going to work on a PR, it would be preferred to let me know ahead of time +(unless it's a quick fix), and open a draft PR if it's a large one. Then I'll +assign the issue to you. Otherwise, I can't guarantee I won't duplicate your +work. If I can't contact you within a week, I may unassign you and finish your +work (opening a Draft PR on this repository puts your code under this crate's +license). + +If you open a bug report, you can usually expect it to be fixed within a week. +If you open a feature request it may stay open indefinitely, until I need it +too. I mark feature requests as "enhancements" on GitHub issues. + +Happy coding! + +[open an issue]: https://github.com/ardaku/whoami/issues +[send me an email]: mailto:aldaronlau@gmail.com +[open a PR]: https://github.com/ardaku/whoami/pulls +[Post to GitHub Discussions]: https://github.com/ardaku/whoami/discussions diff --git a/Cargo.toml b/Cargo.toml index 44941be..e9e6469 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,44 +1,44 @@ -[package] -name = "whoami" -version = "1.4.1" -edition = "2018" -license = "Apache-2.0 OR BSL-1.0 OR MIT" -documentation = "https://docs.rs/whoami" -homepage = "https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md" -repository = "https://github.com/ardaku/whoami" -readme = "README.md" -description = "Retrieve the current user and environment." -keywords = ["user", "username", "whoami", "platform", "detect"] -categories = [ - "os", - "wasm", - "internationalization", - "localization", - "value-formatting", -] -include = [ - "LICENSE_APACHE", - "LICENSE_BOOST", - "LICENSE_MIT", - "README.md", - "src/*", -] -rust-version = "1.40" - -# Target-specific dependency required to work with wasm-bindgen -[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.web-sys] -version = "0.3" -features = ["Navigator", "Document", "Window", "Location"] -optional = true -[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.wasm-bindgen] -version = "0.2" -optional = true - -[features] -default = ["web"] -# Enabling this feature indicates that the wasm32-unknown-unknown target should -# be assumed to be in a web environment where it can call DOM APIs. -web = ["web-sys", "wasm-bindgen"] - -[dependencies] +[package] +name = "whoami" +version = "1.4.1" +edition = "2018" +license = "Apache-2.0 OR BSL-1.0 OR MIT" +documentation = "https://docs.rs/whoami" +homepage = "https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md" +repository = "https://github.com/ardaku/whoami" +readme = "README.md" +description = "Retrieve the current user and environment." +keywords = ["user", "username", "whoami", "platform", "detect"] +categories = [ + "os", + "wasm", + "internationalization", + "localization", + "value-formatting", +] +include = [ + "LICENSE_APACHE", + "LICENSE_BOOST", + "LICENSE_MIT", + "README.md", + "src/*", +] +rust-version = "1.40" + +# Target-specific dependency required to work with wasm-bindgen +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.web-sys] +version = "0.3" +features = ["Navigator", "Document", "Window", "Location"] +optional = true +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.wasm-bindgen] +version = "0.2" +optional = true + +[features] +default = ["web"] +# Enabling this feature indicates that the wasm32-unknown-unknown target should +# be assumed to be in a web environment where it can call DOM APIs. +web = ["web-sys", "wasm-bindgen"] + +[dependencies] ansi_term = "0.12.0" \ No newline at end of file diff --git a/LICENSE_APACHE b/LICENSE_APACHE index a2ce4d9..1b5ec8b 100644 --- a/LICENSE_APACHE +++ b/LICENSE_APACHE @@ -1,176 +1,176 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE_BOOST b/LICENSE_BOOST index 1dad8e9..36b7cd9 100644 --- a/LICENSE_BOOST +++ b/LICENSE_BOOST @@ -1,23 +1,23 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/LICENSE_MIT b/LICENSE_MIT index 9dccfa4..9cf1062 100644 --- a/LICENSE_MIT +++ b/LICENSE_MIT @@ -1,19 +1,19 @@ -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index ef9e741..b8e60d6 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,93 @@ -![WhoAmI Logo](https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg) - -#### [Changelog][3] | [Source][4] | [Getting Started][5] - -[![tests](https://github.com/ardaku/whoami/actions/workflows/ci.yml/badge.svg)](https://github.com/ardaku/whoami/actions/workflows/ci.yml) -[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/ardaku/whoami)](https://github.com/ardaku/whoami/) -[![GitHub contributors](https://img.shields.io/github/contributors/ardaku/whoami)](https://github.com/ardaku/whoami/graphs/contributors) -[![Crates.io](https://img.shields.io/crates/v/whoami)](https://crates.io/crates/whoami) -[![Crates.io](https://img.shields.io/crates/d/whoami)](https://crates.io/crates/whoami) -[![Crates.io (recent)](https://img.shields.io/crates/dr/whoami)](https://crates.io/crates/whoami) -[![Crates.io](https://img.shields.io/crates/l/whoami)](https://github.com/ardaku/whoami/search?l=Text&q=license) -[![Docs.rs](https://docs.rs/whoami/badge.svg)](https://docs.rs/whoami/) - -Retrieve the current user and environment through simple functions. - -Check out the [documentation][0] for examples. - -### Features - - Get the user's full name - - Get the user's username - - Get the user's preferred language(s) - - Get the devices's hostname - - Get the devices's "pretty" or "fancy" name - - Get the devices's desktop environment - - Get the devices's OS name and version - - Get the devices's platform name - - Get the devices's CPU architecture and its width - -### Supported Platforms -WhoAmI targets all platforms that can run Rust, including: - - Linux - - Windows - - Mac OS - - BSD variants (FreeBSD, others) - - [Web Assembly](https://github.com/ardaku/whoami/blob/stable/WASM.md) - - Mock implementation - - Web Browser - DOM - - WASI (Wasite/Quantii, others) **mock implementation, full implementation planned later** - - Daku (Ardaku/Quantii, others) **mock implementation, full implementation planned later** - - Illumos variants (SmartOS, OmniOS, others) **may partially or fully work - but untested** - - Android **may partially or fully work - but untested, planned later** - - iOS **planned later** - - Redox **planned later** - - Fuchsia **planned later** - - Various game consoles **planned later** - - Others? (make a PR or open an issue) - -## MSRV -WhoAmI 1.x.y targets Rust 1.40.0 stable and later, and the 1.x.y track will -be maintained at least until the release of the Rust 2024 edition. - -The MSRV will only be updated on major version bumps, and version 2.0.0 will -target Rust 1.65.0 and later to make use of the `let else` syntax. - -## Binary -[whome](https://crates.io/crates/whome): `whoami` command RiR (Re-written in -Rust) that depends on this crate. - -## License -Copyright © 2017-2023 The WhoAmI Contributors. - -Licensed under any of - - Apache License, Version 2.0, ([LICENSE_APACHE][7] - or [https://www.apache.org/licenses/LICENSE-2.0][8]) - - Boost Software License, Version 1.0, ([LICENSE_BOOST][11] - or [https://www.boost.org/LICENSE_1_0.txt][12]) - - MIT License, ([LICENSE_MIT][9] or [https://mit-license.org/][10]) - -at your option. - -### Contribution -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -licensed as described above, without any additional terms or conditions. - -## Help -If you want help using or contributing to this library, feel free to send me an -email at [aldaronlau@gmail.com][13]. - -[0]: https://docs.rs/whoami -[1]: https://crates.io/crates/whoami -[2]: https://github.com/ardaku/whoami/actions?query=workflow%3Atests -[3]: https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md -[4]: https://github.com/ardaku/whoami/ -[5]: https://docs.rs/whoami#getting-started -[6]: https://aldaronlau.com/ -[7]: https://github.com/ardaku/whoami/blob/stable/LICENSE_APACHE -[8]: https://www.apache.org/licenses/LICENSE-2.0 -[9]: https://github.com/ardaku/whoami/blob/stable/LICENSE_MIT -[10]: https://mit-license.org/ -[11]: https://github.com/ardaku/whoami/blob/stable/LICENSE_BOOST -[12]: https://www.boost.org/LICENSE_1_0.txt -[13]: mailto:aldaronlau@gmail.com +![WhoAmI Logo](https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg) + +#### [Changelog][3] | [Source][4] | [Getting Started][5] + +[![tests](https://github.com/ardaku/whoami/actions/workflows/ci.yml/badge.svg)](https://github.com/ardaku/whoami/actions/workflows/ci.yml) +[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/ardaku/whoami)](https://github.com/ardaku/whoami/) +[![GitHub contributors](https://img.shields.io/github/contributors/ardaku/whoami)](https://github.com/ardaku/whoami/graphs/contributors) +[![Crates.io](https://img.shields.io/crates/v/whoami)](https://crates.io/crates/whoami) +[![Crates.io](https://img.shields.io/crates/d/whoami)](https://crates.io/crates/whoami) +[![Crates.io (recent)](https://img.shields.io/crates/dr/whoami)](https://crates.io/crates/whoami) +[![Crates.io](https://img.shields.io/crates/l/whoami)](https://github.com/ardaku/whoami/search?l=Text&q=license) +[![Docs.rs](https://docs.rs/whoami/badge.svg)](https://docs.rs/whoami/) + +Retrieve the current user and environment through simple functions. + +Check out the [documentation][0] for examples. + +### Features + - Get the user's full name + - Get the user's username + - Get the user's preferred language(s) + - Get the devices's hostname + - Get the devices's "pretty" or "fancy" name + - Get the devices's desktop environment + - Get the devices's OS name and version + - Get the devices's platform name + - Get the devices's CPU architecture and its width + +### Supported Platforms +WhoAmI targets all platforms that can run Rust, including: + - Linux + - Windows + - Mac OS + - BSD variants (FreeBSD, others) + - [Web Assembly](https://github.com/ardaku/whoami/blob/stable/WASM.md) + - Mock implementation + - Web Browser - DOM + - WASI (Wasite/Quantii, others) **mock implementation, full implementation planned later** + - Daku (Ardaku/Quantii, others) **mock implementation, full implementation planned later** + - Illumos variants (SmartOS, OmniOS, others) **may partially or fully work - but untested** + - Android **may partially or fully work - but untested, planned later** + - iOS **planned later** + - Redox **planned later** + - Fuchsia **planned later** + - Various game consoles **planned later** + - Others? (make a PR or open an issue) + +## MSRV +WhoAmI 1.x.y targets Rust 1.40.0 stable and later, and the 1.x.y track will +be maintained at least until the release of the Rust 2024 edition. + +The MSRV will only be updated on major version bumps, and version 2.0.0 will +target Rust 1.65.0 and later to make use of the `let else` syntax. + +## Binary +[whome](https://crates.io/crates/whome): `whoami` command RiR (Re-written in +Rust) that depends on this crate. + +## License +Copyright © 2017-2023 The WhoAmI Contributors. + +Licensed under any of + - Apache License, Version 2.0, ([LICENSE_APACHE][7] + or [https://www.apache.org/licenses/LICENSE-2.0][8]) + - Boost Software License, Version 1.0, ([LICENSE_BOOST][11] + or [https://www.boost.org/LICENSE_1_0.txt][12]) + - MIT License, ([LICENSE_MIT][9] or [https://mit-license.org/][10]) + +at your option. + +### Contribution +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +licensed as described above, without any additional terms or conditions. + +## Help +If you want help using or contributing to this library, feel free to send me an +email at [aldaronlau@gmail.com][13]. + +[0]: https://docs.rs/whoami +[1]: https://crates.io/crates/whoami +[2]: https://github.com/ardaku/whoami/actions?query=workflow%3Atests +[3]: https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md +[4]: https://github.com/ardaku/whoami/ +[5]: https://docs.rs/whoami#getting-started +[6]: https://aldaronlau.com/ +[7]: https://github.com/ardaku/whoami/blob/stable/LICENSE_APACHE +[8]: https://www.apache.org/licenses/LICENSE-2.0 +[9]: https://github.com/ardaku/whoami/blob/stable/LICENSE_MIT +[10]: https://mit-license.org/ +[11]: https://github.com/ardaku/whoami/blob/stable/LICENSE_BOOST +[12]: https://www.boost.org/LICENSE_1_0.txt +[13]: mailto:aldaronlau@gmail.com diff --git a/WASM.md b/WASM.md index c38c95c..1cd9995 100644 --- a/WASM.md +++ b/WASM.md @@ -1,48 +1,48 @@ -# WhoAmI WebAssembly Documentation - -## Web (Browser) -By default, when WhoAmI is compiled for Wasm32 unknown (neither -wasi or -daku), -WhoAmI links to web-sys and defaults values to browser information: - - - `realname()`: "Anonymous" - - `username()`: "anonymous" - - `lang()`: Browser preferred language list - - `devicename()`: Browser name (Example: "Firefox 110.0") - - `hostname()`: "localhost" - - `platform()`: Host operating system by view of browser (Example: "Linux") - - `distro()`: Host distro by view of browser (Example "Unknown Linux") - - `desktop_env()`: "Web Browser" - - `arch()`: "wasm32" - -## Mock -If you compile WhoAmI with `default-features = false`, WhoAmI will not bind to -web-sys, and will instead return these mock values: - - - `realname()`: "Anonymous" - - `username()`: "anonymous" - - `lang()`: "en-US" - - `devicename()`: "Unknown" - - `hostname()`: "localhost" - - `platform()`: "Unknown" - - `distro()`: "Emulated" - - `desktop_env()`: "Unknown WebAssembly" - - `arch()`: "wasm32" - -## Wasi (Wasite) -Building WhoAmI targeting Wasi will assume the -[wasite](https://ardaku.org/wasite/env_vars.html) environment variables are set, -as Wasi alone does not currently support the functionality WhoAmI requires. - - - `realname()`: `$USER` - - `username()`: `$USER` - - `lang()`: `$LANGS` - - `devicename()`: `$NAME` - - `hostname()`: `$HOSTNAME` - - `platform()`: "Wasite" - - `distro()`: "Unknown wasi" - - `desktop_env()`: "Unknown wasite" - - `arch()`: "wasm32" - -## Daku (Quantii, other Ardaku environments) -WhoAmi will depend on currently unstable portals in the -[Daku](https://ardaku.org/daku/) specification. +# WhoAmI WebAssembly Documentation + +## Web (Browser) +By default, when WhoAmI is compiled for Wasm32 unknown (neither -wasi or -daku), +WhoAmI links to web-sys and defaults values to browser information: + + - `realname()`: "Anonymous" + - `username()`: "anonymous" + - `lang()`: Browser preferred language list + - `devicename()`: Browser name (Example: "Firefox 110.0") + - `hostname()`: "localhost" + - `platform()`: Host operating system by view of browser (Example: "Linux") + - `distro()`: Host distro by view of browser (Example "Unknown Linux") + - `desktop_env()`: "Web Browser" + - `arch()`: "wasm32" + +## Mock +If you compile WhoAmI with `default-features = false`, WhoAmI will not bind to +web-sys, and will instead return these mock values: + + - `realname()`: "Anonymous" + - `username()`: "anonymous" + - `lang()`: "en-US" + - `devicename()`: "Unknown" + - `hostname()`: "localhost" + - `platform()`: "Unknown" + - `distro()`: "Emulated" + - `desktop_env()`: "Unknown WebAssembly" + - `arch()`: "wasm32" + +## Wasi (Wasite) +Building WhoAmI targeting Wasi will assume the +[wasite](https://ardaku.org/wasite/env_vars.html) environment variables are set, +as Wasi alone does not currently support the functionality WhoAmI requires. + + - `realname()`: `$USER` + - `username()`: `$USER` + - `lang()`: `$LANGS` + - `devicename()`: `$NAME` + - `hostname()`: `$HOSTNAME` + - `platform()`: "Wasite" + - `distro()`: "Unknown wasi" + - `desktop_env()`: "Unknown wasite" + - `arch()`: "wasm32" + +## Daku (Quantii, other Ardaku environments) +WhoAmi will depend on currently unstable portals in the +[Daku](https://ardaku.org/daku/) specification. diff --git a/examples/os-strings.rs b/examples/os-strings.rs index abbf5d2..158248d 100644 --- a/examples/os-strings.rs +++ b/examples/os-strings.rs @@ -1,42 +1,42 @@ -fn main() { - println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); - println!(); - println!( - "User's Name whoami::realname_os(): {:?}", - whoami::realname_os() - ); - println!( - "User's Username whoami::username_os(): {:?}", - whoami::username() - ); - println!( - "User's Language whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - ); - println!( - "Device's Pretty Name whoami::devicename_os(): {:?}", - whoami::devicename() - ); - println!( - "Device's Hostname whoami::hostname_os(): {:?}", - whoami::hostname() - ); - println!( - "Device's Platform whoami::platform_os(): {:?}", - whoami::platform() - ); - println!( - "Device's OS Distro whoami::distro_os(): {:?}", - whoami::distro() - ); - println!( - "Device's Desktop Env. whoami::desktop_env(): {:?}", - whoami::desktop_env() - ); - println!( - "Device's CPU Arch whoami::arch(): {:?}", - whoami::arch() - ); -} +fn main() { + println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); + println!(); + println!( + "User's Name whoami::realname_os(): {:?}", + whoami::realname_os() + ); + println!( + "User's Username whoami::username_os(): {:?}", + whoami::username() + ); + println!( + "User's Language whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + ); + println!( + "Device's Pretty Name whoami::devicename_os(): {:?}", + whoami::devicename() + ); + println!( + "Device's Hostname whoami::hostname_os(): {:?}", + whoami::hostname() + ); + println!( + "Device's Platform whoami::platform_os(): {:?}", + whoami::platform() + ); + println!( + "Device's OS Distro whoami::distro_os(): {:?}", + whoami::distro() + ); + println!( + "Device's Desktop Env. whoami::desktop_env(): {:?}", + whoami::desktop_env() + ); + println!( + "Device's CPU Arch whoami::arch(): {:?}", + whoami::arch() + ); +} diff --git a/examples/web/Cargo.toml b/examples/web/Cargo.toml index c552342..2f74f75 100644 --- a/examples/web/Cargo.toml +++ b/examples/web/Cargo.toml @@ -1,36 +1,36 @@ -[package] -name = "whoami_web" -version = "0.1.0" -authors = ["Jeron Aldaron Lau "] -edition = "2021" - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -default = ["console_error_panic_hook"] - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for -# code size when deploying. -[dependencies.console_error_panic_hook] -version = "0.1" -optional = true - -# wasm-bindgen lets us export our main function to the javascript that runs the -# web assembly module. -[dependencies.wasm-bindgen] -version = "0.2" - -# The `web-sys` crate lets us log in the web console. -[dependencies.web-sys] -version = "0.3" -features = ["console"] - -# `whoami` - the crate we're testing! -[dependencies.whoami] -path = "../../" - -[profile.release] -opt-level = "s" # Tell `rustc` to optimize for small code size. +[package] +name = "whoami_web" +version = "0.1.0" +authors = ["Jeron Aldaron Lau "] +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["console_error_panic_hook"] + +# The `console_error_panic_hook` crate provides better debugging of panics by +# logging them with `console.error`. This is great for development, but requires +# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for +# code size when deploying. +[dependencies.console_error_panic_hook] +version = "0.1" +optional = true + +# wasm-bindgen lets us export our main function to the javascript that runs the +# web assembly module. +[dependencies.wasm-bindgen] +version = "0.2" + +# The `web-sys` crate lets us log in the web console. +[dependencies.web-sys] +version = "0.3" +features = ["console"] + +# `whoami` - the crate we're testing! +[dependencies.whoami] +path = "../../" + +[profile.release] +opt-level = "s" # Tell `rustc` to optimize for small code size. diff --git a/examples/web/README.md b/examples/web/README.md index 61d1797..b008fc0 100644 --- a/examples/web/README.md +++ b/examples/web/README.md @@ -1,15 +1,15 @@ -# A Web Example - -## Install `wasm-pack` and `http` -```bash -curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -cargo install https -``` - -## Build & Run Web Server -```bash -wasm-pack build --target web && http . -``` - -Now, open http://localhost:8000/ in your web browser and check the javascript -console. +# A Web Example + +## Install `wasm-pack` and `http` +```bash +curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh +cargo install https +``` + +## Build & Run Web Server +```bash +wasm-pack build --target web && http . +``` + +Now, open http://localhost:8000/ in your web browser and check the javascript +console. diff --git a/examples/web/index.html b/examples/web/index.html index d49a157..b23bac6 100644 --- a/examples/web/index.html +++ b/examples/web/index.html @@ -1,14 +1,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/examples/web/rust-toolchain b/examples/web/rust-toolchain index ec19b69..292fe49 100644 --- a/examples/web/rust-toolchain +++ b/examples/web/rust-toolchain @@ -1,2 +1,2 @@ -[toolchain] -channel = "stable" +[toolchain] +channel = "stable" diff --git a/examples/web/src/lib.rs b/examples/web/src/lib.rs index cc783b8..57f996b 100644 --- a/examples/web/src/lib.rs +++ b/examples/web/src/lib.rs @@ -1,57 +1,57 @@ -use wasm_bindgen::prelude::*; - -fn log(text: String) { - web_sys::console::log_1(&text.into()) -} - -#[wasm_bindgen] -pub fn main() { - // When the `console_error_panic_hook` feature is enabled, we can call the - // `set_panic_hook` function at least once during initialization, and then - // we will get better error messages if our code ever panics. - // - // For more details see - // https://github.com/rustwasm/console_error_panic_hook#readme - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); - - // Print out code from regular example. - log(format!( - "User's Name whoami::realname(): {}", - whoami::realname(), - )); - log(format!( - "User's Username whoami::username(): {}", - whoami::username(), - )); - log(format!( - "User's Languages whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - )); - log(format!( - "Device's Pretty Name whoami::devicename(): {}", - whoami::devicename(), - )); - log(format!( - "Device's Hostname whoami::hostname(): {}", - whoami::hostname(), - )); - log(format!( - "Device's Platform whoami::platform(): {}", - whoami::platform(), - )); - log(format!( - "Device's OS Distro whoami::distro(): {}", - whoami::distro(), - )); - log(format!( - "Device's Desktop Env. whoami::desktop_env(): {}", - whoami::desktop_env(), - )); - log(format!( - "Device's CPU Arch whoami::arch(): {}", - whoami::arch(), - )); -} +use wasm_bindgen::prelude::*; + +fn log(text: String) { + web_sys::console::log_1(&text.into()) +} + +#[wasm_bindgen] +pub fn main() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); + + // Print out code from regular example. + log(format!( + "User's Name whoami::realname(): {}", + whoami::realname(), + )); + log(format!( + "User's Username whoami::username(): {}", + whoami::username(), + )); + log(format!( + "User's Languages whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + )); + log(format!( + "Device's Pretty Name whoami::devicename(): {}", + whoami::devicename(), + )); + log(format!( + "Device's Hostname whoami::hostname(): {}", + whoami::hostname(), + )); + log(format!( + "Device's Platform whoami::platform(): {}", + whoami::platform(), + )); + log(format!( + "Device's OS Distro whoami::distro(): {}", + whoami::distro(), + )); + log(format!( + "Device's Desktop Env. whoami::desktop_env(): {}", + whoami::desktop_env(), + )); + log(format!( + "Device's CPU Arch whoami::arch(): {}", + whoami::arch(), + )); +} diff --git a/examples/whoami-demo.rs b/examples/whoami-demo.rs index d5dd518..3472fd3 100644 --- a/examples/whoami-demo.rs +++ b/examples/whoami-demo.rs @@ -1,42 +1,42 @@ -fn main() { - println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); - println!(); - println!( - "User's Name whoami::realname(): {}", - whoami::realname(), - ); - println!( - "User's Username whoami::username(): {}", - whoami::username(), - ); - println!( - "User's Language whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - ); - println!( - "Device's Pretty Name whoami::devicename(): {}", - whoami::devicename(), - ); - println!( - "Device's Hostname whoami::hostname(): {}", - whoami::hostname(), - ); - println!( - "Device's Platform whoami::platform(): {}", - whoami::platform(), - ); - println!( - "Device's OS Distro whoami::distro(): {}", - whoami::distro(), - ); - println!( - "Device's Desktop Env. whoami::desktop_env(): {}", - whoami::desktop_env(), - ); - println!( - "Device's CPU Arch whoami::arch(): {}", - whoami::arch(), - ); -} +fn main() { + println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); + println!(); + println!( + "User's Name whoami::realname(): {}", + whoami::realname(), + ); + println!( + "User's Username whoami::username(): {}", + whoami::username(), + ); + println!( + "User's Language whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + ); + println!( + "Device's Pretty Name whoami::devicename(): {}", + whoami::devicename(), + ); + println!( + "Device's Hostname whoami::hostname(): {}", + whoami::hostname(), + ); + println!( + "Device's Platform whoami::platform(): {}", + whoami::platform(), + ); + println!( + "Device's OS Distro whoami::distro(): {}", + whoami::distro(), + ); + println!( + "Device's Desktop Env. whoami::desktop_env(): {}", + whoami::desktop_env(), + ); + println!( + "Device's CPU Arch whoami::arch(): {}", + whoami::arch(), + ); +} diff --git a/res/icon.svg b/res/icon.svg index 6772500..71fc460 100644 --- a/res/icon.svg +++ b/res/icon.svg @@ -1,108 +1,108 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/rust-toolchain b/rust-toolchain index 8395338..aacef61 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,2 +1,2 @@ -[toolchain] -channel = "1.40.0" +[toolchain] +channel = "1.40.0" diff --git a/src/disp.rs b/src/disp.rs index 5964369..d0727c5 100644 --- a/src/disp.rs +++ b/src/disp.rs @@ -1,250 +1,250 @@ -use ansi_term::Colour; - -pub fn display_windows() -> &'static str { - r#" - .oodMMMM - .oodMMMMMMMMMMMMM - ..oodMMM MMMMMMMMMMMMMMMMMMM - oodMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM .----------------. .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | - | | _____ _____ | || | _____ | || | ____ _____ | || | ________ | || | ____ | || | _____ _____ | || | _______ | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | ||_ _||_ _|| || | |_ _| | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | || ||_ _||_ _|| || | / ___ | | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | | /\ | | | || | | | | || | | \ | | | || | | | `. \ | || | / .--. \ | || | | | /\ | | | || | | (__ \_| | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | |/ \| | | || | | | | || | | |\ \| | | || | | | | | | || | | | | | | || | | |/ \| | | || | '.___`-. | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | /\ | | || | _| |_ | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | || | | /\ | | || | |`\____) | | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | |__/ \__| | || | |_____| | || ||_____|\____| | || | |________.' | || | `.____.' | || | |__/ \__| | || | |_______.' | | - `^^^^^^MMMMMMM MMMMMMMMMMMMMMMMMMM | | | || | | || | | || | | || | | || | | || | | | - ````^^^^ ^^MMMMMMMMMMMMMMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - ````^^^^^^MMMM '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' -"# -} - -pub fn display_bsd() -> &'static str { - r#" - , , - /( )` - \ \___ / | - /- _ `-/ ' - (/\/ \ \ /\ - / / | ` \ - O O ) / | - `-^--'`< ' - (_.) _ ) / .----------------. .----------------. .----------------. - `.___/` / | .--------------. || .--------------. || .--------------. | - `-----' / | | ______ | || | _______ | || | ________ | | - <----. __ / __ \ | | |_ _ \ | || | / ___ | | || | |_ ___ `. | | - <----|====O)))==) \) /==== | | | |_) | | || | | (__ \_| | || | | | `. \ | | - <----' `--' `.__,' \ | | | __'. | || | '.___`-. | || | | | | | | | - | | | | _| |__) | | || | |`\____) | | || | _| |___.' / | | - \ / | | |_______/ | || | |_______.' | || | |________.' | | - ______( (_ / \______ | | | || | | || | | | - ,' ,-----' | \ | '--------------' || '--------------' || '--------------' | - `--{__________) \/ '----------------' '----------------' '----------------' -"# -} - -pub fn display_macos() -> &'static str{ - r#" - ,xNMM. - .OMMMMo - lMM" - .;loddo:. .olloddol;. - cKMMMMMMMMMMNWMMMMMMMMMM0: - .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. .----------------. .----------------. - XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | -;MMMMMMMMMMMMMMMMMMMMMMMM: | | ____ ____ | || | __ | || | ______ | || | ____ | || | _______ | | -:MMMMMMMMMMMMMMMMMMMMMMMM: | ||_ \ / _|| || | / \ | || | .' ___ | | || | .' `. | || | / ___ | | | -.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | \/ | | || | / /\ \ | || | / .' \_| | || | / .--. \ | || | | (__ \_| | | - kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | |\ /| | | || | / ____ \ | || | | | | || | | | | | | || | '.___`-. | | - 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_\/_| |_ | || | _/ / \ \_ | || | \ `.___.'\ | || | \ `--' / | || | |`\____) | | | - 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | ||_____||_____|| || ||____| |____|| || | `._____.' | || | `.____.' | || | |_______.' | | - kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | || | | || | | | - ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - "cooc*" "*coo' '----------------' '----------------' '----------------' '----------------' '----------------' -"# -} - -pub fn display_illumos() -> &'static str { - r#" -' Tw - `h||hnN - \P|||I$N - `P|||$IK, - `%wb$$IPK, - .*b|I$PPKp - `TP@|$KPPKp - `%wwI@K$PPPKw ,pKKKKm>. - "Tb@|$KPPPPKp pPPPK" - "TK@@@@K$PPPPKp,,bPPK - -wppP$$$$PPPPPPPPPPb - ,,pbP$$PPPPPPPPPP - ,,$pPPPPPPPPPPP .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. - ,pKKPPPPPPPPPL | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | - -<4PPPPPPPP | | _____ | || | _____ | || | _____ | || | _____ _____ | || | ____ ____ | || | ____ | || | _______ | | - PPPPPP` | | |_ _| | || | |_ _| | || | |_ _| | || ||_ _||_ _|| || ||_ \ / _|| || | .' `. | || | / ___ | | | - /KPPPM/ | | | | | || | | | | || | | | | || | | | | | | || | | \/ | | || | / .--. \ | || | | (__ \_| | | - ,pKPPPM` | | | | | || | | | _ | || | | | _ | || | | ' ' | | || | | |\ /| | | || | | | | | | || | '.___`-. | | - ,,pKK$PPM | | _| |_ | || | _| |__/ | | || | _| |__/ | | || | \ `--' / | || | _| |_\/_| |_ | || | \ `--' / | || | |`\____) | | | - '''''qK9K | | |_____| | || | |________| | || | |________| | || | `.__.' | || ||_____||_____|| || | `.____.' | || | |_______.' | | - ,p#M",#" | | | || | | || | | || | | || | | || | | || | | | - `` ,pM` | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - '` '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' - "# -} - -pub fn display_ios() -> &'static str { - r#" - ,xNMM. - .OMMMMo - lMM" - .;loddo:. .olloddol;. - cKMMMMMMMMMMNWMMMMMMMMMM0: - .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. - XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. | -;MMMMMMMMMMMMMMMMMMMMMMMM: | | _____ | || | ____ | || | _______ | | -:MMMMMMMMMMMMMMMMMMMMMMMM: | | |_ _| | || | .' `. | || | / ___ | | | -.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | | | || | / .--. \ | || | | (__ \_| | | - kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | | | || | | | | | | || | '.___`-. | | - 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_ | || | \ `--' / | || | |`\____) | | | - 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | | |_____| | || | `.____.' | || | |_______.' | | - kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | | - ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' | - "cooc*" "*coo' '----------------' '----------------' '----------------' -"# -} - -pub fn display_android() -> &'static str { - r#" - -o o- - +hydNNNNdyh+ - +mMMMMMMMMMMMMm+ - `dMMm:NMMMMMMN:mMMd` - hMMMMMMMMMMMMMMMMMMh - .. yyyyyyyyyyyyyyyyyyyy .. -.mMMm`MMMMMMMMMMMMMMMMMMMM`mMMm. -:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. .----------------. -:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | -:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | __ | || | ____ _____ | || | ________ | || | _______ | || | ____ | || | _____ | || | ________ | | -:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | / \ | || ||_ \|_ _| | || | |_ ___ `. | || | |_ __ \ | || | .' `. | || | |_ _| | || | |_ ___ `. | | --MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM- | | / /\ \ | || | | \ | | | || | | | `. \ | || | | |__) | | || | / .--. \ | || | | | | || | | | `. \ | | - +yy+ MMMMMMMMMMMMMMMMMMMM +yy+ | | / ____ \ | || | | |\ \| | | || | | | | | | || | | __ / | || | | | | | | || | | | | || | | | | | | | - mMMMMMMMMMMMMMMMMMMm | | _/ / \ \_ | || | _| |_\ |_ | || | _| |___.' / | || | _| | \ \_ | || | \ `--' / | || | _| |_ | || | _| |___.' / | | - `/++MMMMh++hMMMM++/` | ||____| |____|| || ||_____|\____| | || | |________.' | || | |____| |___| | || | `.____.' | || | |_____| | || | |________.' | | - MMMMo oMMMM | | | || | | || | | || | | || | | || | | || | | | - MMMMo oMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - oNMm- -mMNs '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' -"# -} - -pub fn display_nintendo() -> &'static str { - r#" - .-----------------. .----------------. .-----------------. .----------------. .----------------. .-----------------. .----------------. .----------------. - | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | - | | ____ _____ | || | _____ | || | ____ _____ | || | _________ | || | _________ | || | ____ _____ | || | ________ | || | ____ | | - | ||_ \|_ _| | || | |_ _| | || ||_ \|_ _| | || | | _ _ | | || | |_ ___ | | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | | -⠀⠀⠀⣀⣤⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣤⡀⠀⠀⠀ | | | \ | | | || | | | | || | | \ | | | || | |_/ | | \_| | || | | |_ \_| | || | | \ | | | || | | | `. \ | || | / .--. \ | | -⠀⣠⣾⡿⠛⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠻⣿⣷⡀ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | |⠀ -⢰⣿⡏⠀⠀ ⣶⣶⣆⠀⠀⣶⣶⠀⢰⣶⡆⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣶⣶⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⡄ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | | -⣿⣿⠀⠀⠀⠀⣿⣿⢿⣧⡀⣿⣿⠀⢰⣶⡆⢰⣶⣦⠴⢶⣦⡄⠛⣿⣿⠛⢀⣤⡖⠒⣶⣄⠀⣴⣶⡦⠶⣶⣦⡀⢀⣴⡶⠶⣿⣿⠀⢠⣴⡖⠒⣦⡄⠀⠀⠸⣿⡇ | | _| |_\ |_ | || | _| |_ | || | _| |_\ |_ | || | _| |_ | || | _| |___/ | | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | | -⣿⣿⠀⠀⠀⠀⣿⣿⠀⢻⣿⣿⣿⠀⢸⣿⡇⢸⣿⡏⠀⠈⣿⣿⠀⣿⣿⠀⢾⣿⡟⠛⠛⠛⠂⣿⣿⡇⠀⢸⣿⡇⢸⣿⡇⠀⣿⣿⠀⣿⣿⠀⠀⣿⣿⠀⠀⢠⣿⡇ | ||_____|\____| | || | |_____| | || ||_____|\____| | || | |_____| | || | |_________| | || ||_____|\____| | || | |________.' | || | `.____.' | | -⠸⣿⣇⠀⠀⠀⠿⠿⠀⠀⠹⠿⠿⠀⠸⠿⠇⠸⠿⠇⠀⠠⠿⠿⠀⠿⠿⠀⠈⠻⠧⠤⠿⠟⠀⠿⠿⠇⠀⠸⠿⠇⠘⠿⣧⡤⠿⠿⠀⠘⠿⠧⠴⠿⠋⠀⢀⣾⣿⠃ | | | || | | || | | || | | || | | || | | || | | || | | | -⠀⠙⢿⣷⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣴⣿⡿⠁⠀ | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | -⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠉ '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' - "# -} -pub fn display_xbox() -> &'static str { - r#" -⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣶⣶⣶⣶⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⡀⠀⠈⠉⠛⠿⣿⣿⣿⣿⠿⠛⠉⠁⠀⢀⠀⠀⠀⠀⠀ -⠀⠀⠀⣴⣿⣿⣿⣶⣄⡀⠀⠈⠙⠋⠁⠀⢀⣠⣶⣿⣿⣿⣦⠀⠀⠀ .----------------. .----------------. .----------------. .----------------. -⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠂⠀⠀⠀⠀⠐⢿⣿⣿⣿⣿⣿⣿⣷⡀⠀ | .--------------. || .--------------. || .--------------. || .--------------. | -⠀⣾⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⢀⡀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⣷⠀ | | ____ ____ | || | ______ | || | ____ | || | ____ ____ | | -⢠⣿⣿⣿⣿⣿⡟⠁⠀⠀⢀⣴⣿⣿⣦⡀⠀⠀⠈⢻⣿⣿⣿⣿⣿⡄ | | |_ _||_ _| | || | |_ _ \ | || | .' `. | || | |_ _||_ _| | | -⢸⣿⣿⣿⣿⠏⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠹⣿⣿⣿⣿⡇ | | \ \ / / | || | | |_) | | || | / .--. \ | || | \ \ / / | | -⠘⣿⣿⣿⠏⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠹⣿⣿⣿⠃ | | > `' < | || | | __'. | || | | | | | | || | > `' < | | -⠀⢿⣿⡟⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⢻⣿⡿⠀ | | _/ /'`\ \_ | || | _| |__) | | || | \ `--' / | || | _/ /'`\ \_ | | -⠀⠈⢿⡇⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢸⡿⠁⠀ | | |____||____| | || | |_______/ | || | `.____.' | || | |____||____| | | -⠀⠀⠀⠃⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠘⠀⠀ | | | || | | || | | || | | | -⠀⠀⠀⠀⠈⠛⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠁⠀⠀⠀⠀ | '--------------' || '--------------' || '--------------' || '--------------' | -⠀⠀⠀⠀⠀⠀⠀⠈⠙⠛⠛⠿⠿⠿⠿⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' '----------------' '----------------' - "# -} - -pub fn display_playstation() -> &'static str { - r#" -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣷⣶⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠿⣿⣷⣶⣄⠀⠀⠀⠀⠀ .----------------. .----------------. -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀ | .--------------. || .--------------. | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀ | | ______ | || | _______ | | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀ | | |_ __ \ | || | / ___ | | | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀ | | | |__) | | || | | (__ \_| | | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⠇⠀⠀⠀⠀ | | | ___/ | || | '.___`-. | | -⠀⠀⠀⠀⠀⠀⠀⣀⣤⠀⣿⣿⣿⣿⡇⠀⠈⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ | | _| |_ | || | |`\____) | | | -⠀⢀⣠⣤⣶⣾⣿⣿⡿⠀⣿⣿⣿⣿⡇⠀⢰⣶⣿⣿⣿⠿⠿⢿⣶⣦⣤⡀ | | |_____| | || | |_______.' | | -⢰⣿⣿⣿⡿⠛⠉⢀⣀⠀⣿⣿⣿⣿⡇⠀⠘⠋⠉⠀⣀⣠⣴⣾⣿⣿⣿⠇ | | | || | | | -⠈⠻⠿⣿⣿⣿⣿⣿⠿⠀⣿⣿⣿⣿⡇⠀⢠⣶⣾⣿⣿⡿⠿⠟⠋⠉⠀⠀ | '--------------' || '--------------' | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⢿⡇⠀⠸⠟⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' - "# -} - -pub fn display_redox() -> &'static str { - r#" - ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ - ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ - ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ - ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ - ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▐░▌ - ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ - ▐░█▀▀▀▀█░█▀▀ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌░▌ - ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ - ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ - ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ - ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ - "# -} - -pub fn display_fuchsia() -> &'static str { - r#" - ▄████ ▄█▄ ▄ █ ▄▄▄▄▄ ▄█ ██ - █▀ █▀ ▀▄ █ █ █ ▀▄ ██ █ █ - █▀▀ █ █ █ ▀ ██▀▀█ ▄ ▀▀▀▀▄ ██ █▄▄█ - █ █ █ █▄ ▄▀ █ █ ▀▄▄▄▄▀ ▐█ █ █ - █ █▄ ▄█ ▀███▀ █ ▐ █ - ▀ ▀▀▀ ▀ █ - ▀ - "# -} - -pub fn display_linux() -> &'static str { - r#" - .88888888:. - 88888888.88888. - .8888888888888888. - 888888888888888888 - 88' _`88'_ `88888 - 88 88 88 88 88888 - 88_88_::_88_:88888 - 88:::,::,:::::8888 - 88`:::::::::'`8888 - .88 `::::' 8:88. - 8888 `8:888. - .8888' `888888. - .8888:.. .::. ...:'8888888:. - .8888.' :' `'::`88:88888 - .8888 ' `.888:8888. - 888:8 . 888:88888 .----------------. .----------------. .-----------------. .----------------. .----------------. - .888:88 .: 888:88888: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | - 8888888. :: 88:888888 | | _____ | || | _____ | || | ____ _____ | || | _____ _____ | || | ____ ____ | | - `.::.888. :: .88888888 | | |_ _| | || | |_ _| | || ||_ \|_ _| | || ||_ _||_ _|| || | |_ _||_ _| | | - .::::::.888. :: :::`8888'.:. | | | | | || | | | | || | | \ | | | || | | | | | | || | \ \ / / | | - ::::::::::.888 ' .:::::::::::: | | | | _ | || | | | | || | | |\ \| | | || | | ' ' | | || | > `' < | | - ::::::::::::.8 ' .:8::::::::::::. | | _| |__/ | | || | _| |_ | || | _| |_\ |_ | || | \ `--' / | || | _/ /'`\ \_ | | - .::::::::::::::. .:888::::::::::::: | | |________| | || | |_____| | || ||_____|\____| | || | `.__.' | || | |____||____| | | - :::::::::::::::88:.__..:88888:::::::::::' | | | || | | || | | || | | || | | | - `'.:::::::::::88888888888.88:::::::::' | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - `':::_:' -- '' -'-' `':_::::'` '----------------' '----------------' '----------------' '----------------' '----------------' -"# -} +use ansi_term::Colour; + +pub fn display_windows() -> &'static str { + r#" + .oodMMMM + .oodMMMMMMMMMMMMM + ..oodMMM MMMMMMMMMMMMMMMMMMM + oodMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM .----------------. .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + | | _____ _____ | || | _____ | || | ____ _____ | || | ________ | || | ____ | || | _____ _____ | || | _______ | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | ||_ _||_ _|| || | |_ _| | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | || ||_ _||_ _|| || | / ___ | | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | | /\ | | | || | | | | || | | \ | | | || | | | `. \ | || | / .--. \ | || | | | /\ | | | || | | (__ \_| | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | |/ \| | | || | | | | || | | |\ \| | | || | | | | | | || | | | | | | || | | |/ \| | | || | '.___`-. | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | /\ | | || | _| |_ | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | || | | /\ | | || | |`\____) | | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | |__/ \__| | || | |_____| | || ||_____|\____| | || | |________.' | || | `.____.' | || | |__/ \__| | || | |_______.' | | + `^^^^^^MMMMMMM MMMMMMMMMMMMMMMMMMM | | | || | | || | | || | | || | | || | | || | | | + ````^^^^ ^^MMMMMMMMMMMMMMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + ````^^^^^^MMMM '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_bsd() -> &'static str { + r#" + , , + /( )` + \ \___ / | + /- _ `-/ ' + (/\/ \ \ /\ + / / | ` \ + O O ) / | + `-^--'`< ' + (_.) _ ) / .----------------. .----------------. .----------------. + `.___/` / | .--------------. || .--------------. || .--------------. | + `-----' / | | ______ | || | _______ | || | ________ | | + <----. __ / __ \ | | |_ _ \ | || | / ___ | | || | |_ ___ `. | | + <----|====O)))==) \) /==== | | | |_) | | || | | (__ \_| | || | | | `. \ | | + <----' `--' `.__,' \ | | | __'. | || | '.___`-. | || | | | | | | | + | | | | _| |__) | | || | |`\____) | | || | _| |___.' / | | + \ / | | |_______/ | || | |_______.' | || | |________.' | | + ______( (_ / \______ | | | || | | || | | | + ,' ,-----' | \ | '--------------' || '--------------' || '--------------' | + `--{__________) \/ '----------------' '----------------' '----------------' +"# +} + +pub fn display_macos() -> &'static str{ + r#" + ,xNMM. + .OMMMMo + lMM" + .;loddo:. .olloddol;. + cKMMMMMMMMMMNWMMMMMMMMMM0: + .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. .----------------. .----------------. + XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | +;MMMMMMMMMMMMMMMMMMMMMMMM: | | ____ ____ | || | __ | || | ______ | || | ____ | || | _______ | | +:MMMMMMMMMMMMMMMMMMMMMMMM: | ||_ \ / _|| || | / \ | || | .' ___ | | || | .' `. | || | / ___ | | | +.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | \/ | | || | / /\ \ | || | / .' \_| | || | / .--. \ | || | | (__ \_| | | + kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | |\ /| | | || | / ____ \ | || | | | | || | | | | | | || | '.___`-. | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_\/_| |_ | || | _/ / \ \_ | || | \ `.___.'\ | || | \ `--' / | || | |`\____) | | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | ||_____||_____|| || ||____| |____|| || | `._____.' | || | `.____.' | || | |_______.' | | + kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | || | | || | | | + ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + "cooc*" "*coo' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_illumos() -> &'static str { + r#" +' Tw + `h||hnN + \P|||I$N + `P|||$IK, + `%wb$$IPK, + .*b|I$PPKp + `TP@|$KPPKp + `%wwI@K$PPPKw ,pKKKKm>. + "Tb@|$KPPPPKp pPPPK" + "TK@@@@K$PPPPKp,,bPPK + -wppP$$$$PPPPPPPPPPb + ,,pbP$$PPPPPPPPPP + ,,$pPPPPPPPPPPP .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. + ,pKKPPPPPPPPPL | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + -<4PPPPPPPP | | _____ | || | _____ | || | _____ | || | _____ _____ | || | ____ ____ | || | ____ | || | _______ | | + PPPPPP` | | |_ _| | || | |_ _| | || | |_ _| | || ||_ _||_ _|| || ||_ \ / _|| || | .' `. | || | / ___ | | | + /KPPPM/ | | | | | || | | | | || | | | | || | | | | | | || | | \/ | | || | / .--. \ | || | | (__ \_| | | + ,pKPPPM` | | | | | || | | | _ | || | | | _ | || | | ' ' | | || | | |\ /| | | || | | | | | | || | '.___`-. | | + ,,pKK$PPM | | _| |_ | || | _| |__/ | | || | _| |__/ | | || | \ `--' / | || | _| |_\/_| |_ | || | \ `--' / | || | |`\____) | | | + '''''qK9K | | |_____| | || | |________| | || | |________| | || | `.__.' | || ||_____||_____|| || | `.____.' | || | |_______.' | | + ,p#M",#" | | | || | | || | | || | | || | | || | | || | | | + `` ,pM` | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + '` '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' + "# +} + +pub fn display_ios() -> &'static str { + r#" + ,xNMM. + .OMMMMo + lMM" + .;loddo:. .olloddol;. + cKMMMMMMMMMMNWMMMMMMMMMM0: + .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. + XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. | +;MMMMMMMMMMMMMMMMMMMMMMMM: | | _____ | || | ____ | || | _______ | | +:MMMMMMMMMMMMMMMMMMMMMMMM: | | |_ _| | || | .' `. | || | / ___ | | | +.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | | | || | / .--. \ | || | | (__ \_| | | + kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | | | || | | | | | | || | '.___`-. | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_ | || | \ `--' / | || | |`\____) | | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | | |_____| | || | `.____.' | || | |_______.' | | + kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | | + ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' | + "cooc*" "*coo' '----------------' '----------------' '----------------' +"# +} + +pub fn display_android() -> &'static str { + r#" + -o o- + +hydNNNNdyh+ + +mMMMMMMMMMMMMm+ + `dMMm:NMMMMMMN:mMMd` + hMMMMMMMMMMMMMMMMMMh + .. yyyyyyyyyyyyyyyyyyyy .. +.mMMm`MMMMMMMMMMMMMMMMMMMM`mMMm. +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. .----------------. +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | __ | || | ____ _____ | || | ________ | || | _______ | || | ____ | || | _____ | || | ________ | | +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | / \ | || ||_ \|_ _| | || | |_ ___ `. | || | |_ __ \ | || | .' `. | || | |_ _| | || | |_ ___ `. | | +-MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM- | | / /\ \ | || | | \ | | | || | | | `. \ | || | | |__) | | || | / .--. \ | || | | | | || | | | `. \ | | + +yy+ MMMMMMMMMMMMMMMMMMMM +yy+ | | / ____ \ | || | | |\ \| | | || | | | | | | || | | __ / | || | | | | | | || | | | | || | | | | | | | + mMMMMMMMMMMMMMMMMMMm | | _/ / \ \_ | || | _| |_\ |_ | || | _| |___.' / | || | _| | \ \_ | || | \ `--' / | || | _| |_ | || | _| |___.' / | | + `/++MMMMh++hMMMM++/` | ||____| |____|| || ||_____|\____| | || | |________.' | || | |____| |___| | || | `.____.' | || | |_____| | || | |________.' | | + MMMMo oMMMM | | | || | | || | | || | | || | | || | | || | | | + MMMMo oMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + oNMm- -mMNs '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_nintendo() -> &'static str { + r#" + .-----------------. .----------------. .-----------------. .----------------. .----------------. .-----------------. .----------------. .----------------. + | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + | | ____ _____ | || | _____ | || | ____ _____ | || | _________ | || | _________ | || | ____ _____ | || | ________ | || | ____ | | + | ||_ \|_ _| | || | |_ _| | || ||_ \|_ _| | || | | _ _ | | || | |_ ___ | | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | | +⠀⠀⠀⣀⣤⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣤⡀⠀⠀⠀ | | | \ | | | || | | | | || | | \ | | | || | |_/ | | \_| | || | | |_ \_| | || | | \ | | | || | | | `. \ | || | / .--. \ | | +⠀⣠⣾⡿⠛⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠻⣿⣷⡀ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | |⠀ +⢰⣿⡏⠀⠀ ⣶⣶⣆⠀⠀⣶⣶⠀⢰⣶⡆⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣶⣶⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⡄ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | | +⣿⣿⠀⠀⠀⠀⣿⣿⢿⣧⡀⣿⣿⠀⢰⣶⡆⢰⣶⣦⠴⢶⣦⡄⠛⣿⣿⠛⢀⣤⡖⠒⣶⣄⠀⣴⣶⡦⠶⣶⣦⡀⢀⣴⡶⠶⣿⣿⠀⢠⣴⡖⠒⣦⡄⠀⠀⠸⣿⡇ | | _| |_\ |_ | || | _| |_ | || | _| |_\ |_ | || | _| |_ | || | _| |___/ | | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | | +⣿⣿⠀⠀⠀⠀⣿⣿⠀⢻⣿⣿⣿⠀⢸⣿⡇⢸⣿⡏⠀⠈⣿⣿⠀⣿⣿⠀⢾⣿⡟⠛⠛⠛⠂⣿⣿⡇⠀⢸⣿⡇⢸⣿⡇⠀⣿⣿⠀⣿⣿⠀⠀⣿⣿⠀⠀⢠⣿⡇ | ||_____|\____| | || | |_____| | || ||_____|\____| | || | |_____| | || | |_________| | || ||_____|\____| | || | |________.' | || | `.____.' | | +⠸⣿⣇⠀⠀⠀⠿⠿⠀⠀⠹⠿⠿⠀⠸⠿⠇⠸⠿⠇⠀⠠⠿⠿⠀⠿⠿⠀⠈⠻⠧⠤⠿⠟⠀⠿⠿⠇⠀⠸⠿⠇⠘⠿⣧⡤⠿⠿⠀⠘⠿⠧⠴⠿⠋⠀⢀⣾⣿⠃ | | | || | | || | | || | | || | | || | | || | | || | | | +⠀⠙⢿⣷⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣴⣿⡿⠁⠀ | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | +⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠉ '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' + "# +} +pub fn display_xbox() -> &'static str { + r#" +⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣶⣶⣶⣶⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⡀⠀⠈⠉⠛⠿⣿⣿⣿⣿⠿⠛⠉⠁⠀⢀⠀⠀⠀⠀⠀ +⠀⠀⠀⣴⣿⣿⣿⣶⣄⡀⠀⠈⠙⠋⠁⠀⢀⣠⣶⣿⣿⣿⣦⠀⠀⠀ .----------------. .----------------. .----------------. .----------------. +⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠂⠀⠀⠀⠀⠐⢿⣿⣿⣿⣿⣿⣿⣷⡀⠀ | .--------------. || .--------------. || .--------------. || .--------------. | +⠀⣾⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⢀⡀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⣷⠀ | | ____ ____ | || | ______ | || | ____ | || | ____ ____ | | +⢠⣿⣿⣿⣿⣿⡟⠁⠀⠀⢀⣴⣿⣿⣦⡀⠀⠀⠈⢻⣿⣿⣿⣿⣿⡄ | | |_ _||_ _| | || | |_ _ \ | || | .' `. | || | |_ _||_ _| | | +⢸⣿⣿⣿⣿⠏⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠹⣿⣿⣿⣿⡇ | | \ \ / / | || | | |_) | | || | / .--. \ | || | \ \ / / | | +⠘⣿⣿⣿⠏⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠹⣿⣿⣿⠃ | | > `' < | || | | __'. | || | | | | | | || | > `' < | | +⠀⢿⣿⡟⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⢻⣿⡿⠀ | | _/ /'`\ \_ | || | _| |__) | | || | \ `--' / | || | _/ /'`\ \_ | | +⠀⠈⢿⡇⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢸⡿⠁⠀ | | |____||____| | || | |_______/ | || | `.____.' | || | |____||____| | | +⠀⠀⠀⠃⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠘⠀⠀ | | | || | | || | | || | | | +⠀⠀⠀⠀⠈⠛⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠁⠀⠀⠀⠀ | '--------------' || '--------------' || '--------------' || '--------------' | +⠀⠀⠀⠀⠀⠀⠀⠈⠙⠛⠛⠿⠿⠿⠿⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' '----------------' '----------------' + "# +} + +pub fn display_playstation() -> &'static str { + r#" +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣷⣶⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠿⣿⣷⣶⣄⠀⠀⠀⠀⠀ .----------------. .----------------. +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀ | .--------------. || .--------------. | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀ | | ______ | || | _______ | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀ | | |_ __ \ | || | / ___ | | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀ | | | |__) | | || | | (__ \_| | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⠇⠀⠀⠀⠀ | | | ___/ | || | '.___`-. | | +⠀⠀⠀⠀⠀⠀⠀⣀⣤⠀⣿⣿⣿⣿⡇⠀⠈⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ | | _| |_ | || | |`\____) | | | +⠀⢀⣠⣤⣶⣾⣿⣿⡿⠀⣿⣿⣿⣿⡇⠀⢰⣶⣿⣿⣿⠿⠿⢿⣶⣦⣤⡀ | | |_____| | || | |_______.' | | +⢰⣿⣿⣿⡿⠛⠉⢀⣀⠀⣿⣿⣿⣿⡇⠀⠘⠋⠉⠀⣀⣠⣴⣾⣿⣿⣿⠇ | | | || | | | +⠈⠻⠿⣿⣿⣿⣿⣿⠿⠀⣿⣿⣿⣿⡇⠀⢠⣶⣾⣿⣿⡿⠿⠟⠋⠉⠀⠀ | '--------------' || '--------------' | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⢿⡇⠀⠸⠟⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' + "# +} + +pub fn display_redox() -> &'static str { + r#" + ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ + ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ + ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▐░▌ + ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ + ▐░█▀▀▀▀█░█▀▀ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌░▌ + ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ + ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ + "# +} + +pub fn display_fuchsia() -> &'static str { + r#" + ▄████ ▄█▄ ▄ █ ▄▄▄▄▄ ▄█ ██ + █▀ █▀ ▀▄ █ █ █ ▀▄ ██ █ █ + █▀▀ █ █ █ ▀ ██▀▀█ ▄ ▀▀▀▀▄ ██ █▄▄█ + █ █ █ █▄ ▄▀ █ █ ▀▄▄▄▄▀ ▐█ █ █ + █ █▄ ▄█ ▀███▀ █ ▐ █ + ▀ ▀▀▀ ▀ █ + ▀ + "# +} + +pub fn display_linux() -> &'static str { + r#" + .88888888:. + 88888888.88888. + .8888888888888888. + 888888888888888888 + 88' _`88'_ `88888 + 88 88 88 88 88888 + 88_88_::_88_:88888 + 88:::,::,:::::8888 + 88`:::::::::'`8888 + .88 `::::' 8:88. + 8888 `8:888. + .8888' `888888. + .8888:.. .::. ...:'8888888:. + .8888.' :' `'::`88:88888 + .8888 ' `.888:8888. + 888:8 . 888:88888 .----------------. .----------------. .-----------------. .----------------. .----------------. + .888:88 .: 888:88888: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + 8888888. :: 88:888888 | | _____ | || | _____ | || | ____ _____ | || | _____ _____ | || | ____ ____ | | + `.::.888. :: .88888888 | | |_ _| | || | |_ _| | || ||_ \|_ _| | || ||_ _||_ _|| || | |_ _||_ _| | | + .::::::.888. :: :::`8888'.:. | | | | | || | | | | || | | \ | | | || | | | | | | || | \ \ / / | | + ::::::::::.888 ' .:::::::::::: | | | | _ | || | | | | || | | |\ \| | | || | | ' ' | | || | > `' < | | + ::::::::::::.8 ' .:8::::::::::::. | | _| |__/ | | || | _| |_ | || | _| |_\ |_ | || | \ `--' / | || | _/ /'`\ \_ | | + .::::::::::::::. .:888::::::::::::: | | |________| | || | |_____| | || ||_____|\____| | || | `.__.' | || | |____||____| | | + :::::::::::::::88:.__..:88888:::::::::::' | | | || | | || | | || | | || | | | + `'.:::::::::::88888888888.88:::::::::' | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + `':::_:' -- '' -'-' `':_::::'` '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} diff --git a/src/fake.rs b/src/fake.rs index 6a28b05..0fe5e1a 100644 --- a/src/fake.rs +++ b/src/fake.rs @@ -1,75 +1,75 @@ -//! Currently used for WebAssembly unknown (non-web) only - -#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] -compile_error!("Unexpected pointer width for target platform"); - -use std::ffi::OsString; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - std::iter::once("en-US".to_string()) -} - -#[inline(always)] -pub(crate) fn username_os() -> Result { - Ok(username()?.into()) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - Ok(realname()?.into()) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[inline(always)] -pub(crate) fn distro_os() -> Result { - Ok(distro()?.into()) -} - -#[inline(always)] -pub(crate) fn username() -> Result { - Ok("anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok("Anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn devicename() -> Result { - Ok("Unknown".to_string()) -} - -#[inline(always)] -pub(crate) fn hostname() -> Result { - Ok("localhost".to_string()) -} - -#[inline(always)] -pub(crate) fn distro() -> Result { - Ok("Emulated".to_string()) -} - -#[inline(always)] -pub(crate) fn desktop_env() -> DesktopEnv { - DesktopEnv::Unknown("WebAssembly".to_string()) -} - -pub(crate) fn platform() -> Platform { - Platform::Unknown("Unknown".to_string()) -} - -pub(crate) fn arch() -> Arch { - if cfg!(target_pointer_width = "64") { - Arch::Wasm64 - } else { - Arch::Wasm32 - } -} +//! Currently used for WebAssembly unknown (non-web) only + +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("Unexpected pointer width for target platform"); + +use std::ffi::OsString; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + std::iter::once("en-US".to_string()) +} + +#[inline(always)] +pub(crate) fn username_os() -> Result { + Ok(username()?.into()) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + Ok(realname()?.into()) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[inline(always)] +pub(crate) fn distro_os() -> Result { + Ok(distro()?.into()) +} + +#[inline(always)] +pub(crate) fn username() -> Result { + Ok("anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok("Anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn devicename() -> Result { + Ok("Unknown".to_string()) +} + +#[inline(always)] +pub(crate) fn hostname() -> Result { + Ok("localhost".to_string()) +} + +#[inline(always)] +pub(crate) fn distro() -> Result { + Ok("Emulated".to_string()) +} + +#[inline(always)] +pub(crate) fn desktop_env() -> DesktopEnv { + DesktopEnv::Unknown("WebAssembly".to_string()) +} + +pub(crate) fn platform() -> Platform { + Platform::Unknown("Unknown".to_string()) +} + +pub(crate) fn arch() -> Arch { + if cfg!(target_pointer_width = "64") { + Arch::Wasm64 + } else { + Arch::Wasm32 + } +} diff --git a/src/fallible.rs b/src/fallible.rs index 393e442..5279c99 100644 --- a/src/fallible.rs +++ b/src/fallible.rs @@ -1,97 +1,97 @@ -//! Fallible versions of the whoami APIs. -//! -//! Some of the functions in the root module will return "Unknown" or -//! "localhost" on error. This might not be desirable in some situations. The -//! functions in this module all return a [`Result`]. - -use std::ffi::OsString; - -use crate::{platform, Result}; - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname()`] most notably in that spaces -/// are not allowed in the username. -#[inline(always)] -pub fn username() -> Result { - platform::username() -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname_os()`] most notably in that -/// spaces are not allowed in the username. -#[inline(always)] -pub fn username_os() -> Result { - platform::username_os() -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname() -> Result { - platform::realname() -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname_os() -> Result { - platform::realname_os() -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro() -> Result { - platform::distro() -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro_os() -> Result { - platform::distro_os() -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename() -> Result { - platform::devicename() -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename_os() -> Result { - platform::devicename_os() -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname() -> Result { - let mut hostname = platform::hostname()?; - - hostname.make_ascii_lowercase(); - - Ok(hostname) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname_os() -> Result { - Ok(hostname()?.into()) -} +//! Fallible versions of the whoami APIs. +//! +//! Some of the functions in the root module will return "Unknown" or +//! "localhost" on error. This might not be desirable in some situations. The +//! functions in this module all return a [`Result`]. + +use std::ffi::OsString; + +use crate::{platform, Result}; + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname()`] most notably in that spaces +/// are not allowed in the username. +#[inline(always)] +pub fn username() -> Result { + platform::username() +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname_os()`] most notably in that +/// spaces are not allowed in the username. +#[inline(always)] +pub fn username_os() -> Result { + platform::username_os() +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname() -> Result { + platform::realname() +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname_os() -> Result { + platform::realname_os() +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro() -> Result { + platform::distro() +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro_os() -> Result { + platform::distro_os() +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename() -> Result { + platform::devicename() +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename_os() -> Result { + platform::devicename_os() +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname() -> Result { + let mut hostname = platform::hostname()?; + + hostname.make_ascii_lowercase(); + + Ok(hostname) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname_os() -> Result { + Ok(hostname()?.into()) +} diff --git a/src/lib.rs b/src/lib.rs index 4ee27ca..aeb35b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,600 +1,600 @@ -//! Crate for getting the user's username, realname and environment. -//! -//! ## Getting Started -//! Using the whoami crate is super easy! All of the public items are simple -//! functions with no parameters that return [`String`]s or [`OsString`]s (with -//! the exception of [`desktop_env()`], [`platform()`], and [`arch()`], which -//! return enums, and [`lang()`] that returns an iterator of [`String`]s). The -//! following example shows how to use all of the functions (except those that -//! return [`OsString`]): -//! -//! ```rust -//! println!( -//! "User's Name whoami::realname(): {}", -//! whoami::realname(), -//! ); -//! println!( -//! "User's Username whoami::username(): {}", -//! whoami::username(), -//! ); -//! println!( -//! "User's Language whoami::lang(): {:?}", -//! whoami::lang().collect::>(), -//! ); -//! println!( -//! "Device's Pretty Name whoami::devicename(): {}", -//! whoami::devicename(), -//! ); -//! println!( -//! "Device's Hostname whoami::hostname(): {}", -//! whoami::hostname(), -//! ); -//! println!( -//! "Device's Platform whoami::platform(): {}", -//! whoami::platform(), -//! ); -//! println!( -//! "Device's OS Distro whoami::distro(): {}", -//! whoami::distro(), -//! ); -//! println!( -//! "Device's Desktop Env. whoami::desktop_env(): {}", -//! whoami::desktop_env(), -//! ); -//! println!( -//! "Device's CPU Arch whoami::arch(): {}", -//! whoami::arch(), -//! ); -//! ``` - -#![warn( - anonymous_parameters, - missing_copy_implementations, - missing_debug_implementations, - missing_docs, - nonstandard_style, - rust_2018_idioms, - single_use_lifetimes, - trivial_casts, - trivial_numeric_casts, - unreachable_pub, - unused_extern_crates, - unused_qualifications, - variant_size_differences, - unsafe_code -)] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg", - html_favicon_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg" -)] - -const DEFAULT_USERNAME: &str = "Unknown"; -const DEFAULT_HOSTNAME: &str = "LocalHost"; - -pub mod fallible; -pub mod disp; - -#[allow(unsafe_code)] -// Unix -#[cfg_attr( - not(any(target_os = "windows", target_arch = "wasm32")), - path = "unix.rs" -)] -// Wasm32 (Daku) - FIXME: Currently routes to fake.rs -#[cfg_attr(all(target_arch = "wasm32", target_os = "daku"), path = "fake.rs")] -// Wasm32 (Wasi) - FIXME: Currently routes to fake.rs -#[cfg_attr(all(target_arch = "wasm32", target_os = "wasi"), path = "fake.rs")] -// Wasm32 (Web) -#[cfg_attr( - all( - target_arch = "wasm32", - not(target_os = "wasi"), - not(target_os = "daku"), - feature = "web", - ), - path = "web.rs" -)] -// Wasm32 (Unknown) -#[cfg_attr( - all( - target_arch = "wasm32", - not(target_os = "wasi"), - not(target_os = "daku"), - not(feature = "web"), - ), - path = "fake.rs" -)] -// Windows -#[cfg_attr( - all(target_os = "windows", not(target_arch = "wasm32")), - path = "windows.rs" -)] -mod platform; - -use std::{ - ffi::OsString, - fmt::{self, Display, Formatter}, - io::{Error, ErrorKind}, -}; - -/// This crate's convenience type alias for [`Result`](std::result::Result)s -pub type Result = std::result::Result; - -/// Region code for a [`Language`] dialect -/// -/// Uses -#[non_exhaustive] -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum Region { - // FIXME: V2: u32::from_ne_bytes for region codes, with `\0` for unused - // FIXME: Add aliases up to 3-4 letters, but hidden - /// Any dialect - Any, - /// `US`: United States of America - #[doc(hidden)] - Us, -} - -impl Display for Region { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Self::Any => "**", - Self::Us => "US", - }) - } -} - -/// A spoken language -/// -/// Use [`ToString::to_string()`] to convert to string of two letter lowercase -/// language code followed and underscore and uppercase region code (example: -/// `en_US`). -/// -/// Uses -#[non_exhaustive] -#[derive(Clone, Eq, PartialEq, Debug)] -// #[allow(variant_size_differences)] -pub enum Language { - #[doc(hidden)] - __(Box), - /// `en`: English - #[doc(hidden)] - En(Region), - /// `es`: Spanish - #[doc(hidden)] - Es(Region), -} - -impl Language { - /// Retrieve the region code for this language dialect. - pub fn region(&self) -> Region { - match self { - Self::__(_) => Region::Any, - Self::En(region) | Self::Es(region) => *region, - } - } -} - -impl Display for Language { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::__(code) => f.write_str(code.as_str()), - Self::En(region) => { - if *region != Region::Any { - f.write_str("en_")?; - ::fmt(region, f) - } else { - f.write_str("en") - } - } - Self::Es(region) => { - if *region != Region::Any { - f.write_str("es_")?; - ::fmt(region, f) - } else { - f.write_str("es") - } - } - } - } -} - -// FIXME: V2: Move `Unknown` variants to the top of the enum. - -/// The desktop environment of a system -#[derive(Debug, PartialEq, Eq, Clone)] -#[non_exhaustive] -pub enum DesktopEnv { - /// Popular GTK-based desktop environment on Linux - Gnome, - /// One of the desktop environments for a specific version of Windows - Windows, - /// Linux desktop environment optimized for low resource requirements - Lxde, - /// Stacking window manager for X Windows on Linux - Openbox, - /// Desktop environment for Linux, BSD and Illumos - Mate, - /// Lightweight desktop enivornment for unix-like operating systems - Xfce, - /// KDE Plasma desktop enviroment - // FIXME: Rename to 'Plasma' in whoami 2.0.0 - Kde, - /// Default desktop environment on Linux Mint - Cinnamon, - /// Tiling window manager for Linux - I3, - /// Desktop environment for MacOS - Aqua, - /// Desktop environment for iOS - Ios, - /// Desktop environment for Android - Android, - /// Running as Web Assembly on a web page - WebBrowser, - /// A desktop environment for a video game console - Console, - /// Ubuntu-branded GNOME - Ubuntu, - /// Default shell for Fuchsia - Ermine, - /// Default desktop environment for Redox - Orbital, - /// Unknown desktop environment - Unknown(String), -} - -impl Display for DesktopEnv { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::Gnome => "Gnome", - Self::Windows => "Windows", - Self::Lxde => "LXDE", - Self::Openbox => "Openbox", - Self::Mate => "Mate", - Self::Xfce => "XFCE", - Self::Kde => "KDE", - Self::Cinnamon => "Cinnamon", - Self::I3 => "I3", - Self::Aqua => "Aqua", - Self::Ios => "IOS", - Self::Android => "Android", - Self::WebBrowser => "Web Browser", - Self::Console => "Console", - Self::Ubuntu => "Ubuntu", - Self::Ermine => "Ermine", - Self::Orbital => "Orbital", - Self::Unknown(a) => a, - }) - } -} - -/// The underlying platform for a system -#[allow(missing_docs)] -#[derive(Debug, PartialEq, Eq, Clone)] -#[non_exhaustive] -pub enum Platform { - Linux, - Bsd, - Windows, - // FIXME: Non-standard casing; Rename to 'Mac' rather than 'MacOs' in - // whoami 2.0.0 - MacOS, - Illumos, - Ios, - Android, - Nintendo, - Xbox, - PlayStation, - Fuchsia, - Redox, - Unknown(String), -} - -impl Display for Platform { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::Linux => disp::display_linux(), - Self::Bsd => disp::display_bsd(), - Self::Windows => disp::display_windows(), - Self::MacOS => disp::display_macos(), - Self::Illumos => disp::display_illumos(), - Self::Ios => disp::display_ios(), - Self::Android => disp::display_android(), - Self::Nintendo => disp::display_nintendo(), - Self::Xbox => disp::display_xbox(), - Self::PlayStation => disp::display_playstation(), - Self::Fuchsia => disp::display_fuchsia(), - Self::Redox => disp::display_redox(), - Self::Unknown(a) => a, - }) - } -} - -/// The architecture of a CPU -#[non_exhaustive] -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Arch { - /// ARMv5 - ArmV5, - /// ARMv6 (Sometimes just referred to as ARM) - ArmV6, - /// ARMv7 (May or may not support Neon/Thumb) - ArmV7, - /// ARM64 (aarch64) - Arm64, - /// i386 (x86) - I386, - /// i586 (x86) - I586, - /// i686 (x86) - I686, - /// X86_64 / Amd64 - X64, - /// MIPS - Mips, - /// MIPS (LE) - MipsEl, - /// MIPS64 - Mips64, - /// MIPS64 (LE) - Mips64El, - /// PowerPC - PowerPc, - /// PowerPC64 - PowerPc64, - /// PowerPC64LE - PowerPc64Le, - /// 32-bit RISC-V - Riscv32, - /// 64-bit RISC-V - Riscv64, - /// S390x - S390x, - /// SPARC - Sparc, - /// SPARC64 - Sparc64, - /// 32-bit Web Assembly - Wasm32, - /// 64-bit Web Assembly - Wasm64, - /// Unknown Architecture - Unknown(String), -} - -impl Display for Arch { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::ArmV5 => "armv5", - Self::ArmV6 => "armv6", - Self::ArmV7 => "armv7", - Self::Arm64 => "arm64", - Self::I386 => "i386", - Self::I586 => "i586", - Self::I686 => "i686", - Self::Mips => "mips", - Self::MipsEl => "mipsel", - Self::Mips64 => "mips64", - Self::Mips64El => "mips64el", - Self::PowerPc => "powerpc", - Self::PowerPc64 => "powerpc64", - Self::PowerPc64Le => "powerpc64le", - Self::Riscv32 => "riscv32", - Self::Riscv64 => "riscv64", - Self::S390x => "s390x", - Self::Sparc => "sparc", - Self::Sparc64 => "sparc64", - Self::Wasm32 => "wasm32", - Self::Wasm64 => "wasm64", - Self::X64 => "x86_64", - Self::Unknown(arch) => arch, - }) - } -} - -/// The address width of a CPU architecture -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[non_exhaustive] -pub enum Width { - /// 32 bits - Bits32, - /// 64 bits - Bits64, -} - -impl Display for Width { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Width::Bits32 => "32 bits", - Width::Bits64 => "64 bits", - }) - } -} - -impl Arch { - /// Get the width of this architecture. - pub fn width(&self) -> Result { - match self { - Arch::ArmV5 - | Arch::ArmV6 - | Arch::ArmV7 - | Arch::I386 - | Arch::I586 - | Arch::I686 - | Arch::Mips - | Arch::MipsEl - | Arch::PowerPc - | Arch::Riscv32 - | Arch::Sparc - | Arch::Wasm32 => Ok(Width::Bits32), - Arch::Arm64 - | Arch::Mips64 - | Arch::Mips64El - | Arch::PowerPc64 - | Arch::PowerPc64Le - | Arch::Riscv64 - | Arch::S390x - | Arch::Sparc64 - | Arch::Wasm64 - | Arch::X64 => Ok(Width::Bits64), - Arch::Unknown(unknown_arch) => Err(Error::new( - ErrorKind::InvalidData, - format!( - "Tried getting width of unknown arch ({})", - unknown_arch, - ), - )), - } - } -} - -/// Get the CPU Architecture. -#[inline(always)] -pub fn arch() -> Arch { - platform::arch() -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname()`] most notably in that spaces -/// are not allowed in the username. -#[inline(always)] -pub fn username() -> String { - fallible::username().unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase()) -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname_os()`] most notably in that -/// spaces are not allowed in the username. -#[inline(always)] -pub fn username_os() -> OsString { - fallible::username_os() - .unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase().into()) -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname() -> String { - fallible::realname() - .or_else(|_| fallible::username()) - .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned()) -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname_os() -> OsString { - fallible::realname_os() - .or_else(|_| fallible::username_os()) - .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into()) -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename() -> String { - fallible::devicename() - .or_else(|_| fallible::hostname()) - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string()) -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename_os() -> OsString { - fallible::devicename_os() - .or_else(|_| fallible::hostname_os()) - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into()) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname() -> String { - fallible::hostname().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase()) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname_os() -> OsString { - fallible::hostname_os() - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase().into()) -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro() -> String { - fallible::distro().unwrap_or_else(|_| format!("Unknown {}", platform())) -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro_os() -> OsString { - fallible::distro_os() - .unwrap_or_else(|_| format!("Unknown {}", platform()).into()) -} - -/// Get the desktop environment. -/// -/// Example: "gnome" or "windows" -#[inline(always)] -pub fn desktop_env() -> DesktopEnv { - platform::desktop_env() -} - -/// Get the platform. -#[inline(always)] -pub fn platform() -> Platform { - platform::platform() -} - -/// Get the user's preferred language(s). -/// -/// Returned as iterator of two letter language codes (lowercase), optionally -/// followed by a dash (-) and a two letter region code (uppercase). The most -/// preferred language is returned first, followed by next preferred, and so on. -#[inline(always)] -#[deprecated(note = "use `langs()` instead", since = "1.5.0")] -pub fn lang() -> impl Iterator { - platform::lang() -} - -/// Get the user's preferred language(s). -/// -/// Returned as iterator of [`Language`]s wrapped in [`Result`]s. The most -/// preferred language is returned first, followed by next preferred, and so on. -/// Unrecognized languages may return an error. -#[inline(always)] -pub fn langs() -> impl Iterator> { - #[allow(deprecated)] - lang().map(|string| Ok(Language::__(Box::new(string)))) -} +//! Crate for getting the user's username, realname and environment. +//! +//! ## Getting Started +//! Using the whoami crate is super easy! All of the public items are simple +//! functions with no parameters that return [`String`]s or [`OsString`]s (with +//! the exception of [`desktop_env()`], [`platform()`], and [`arch()`], which +//! return enums, and [`lang()`] that returns an iterator of [`String`]s). The +//! following example shows how to use all of the functions (except those that +//! return [`OsString`]): +//! +//! ```rust +//! println!( +//! "User's Name whoami::realname(): {}", +//! whoami::realname(), +//! ); +//! println!( +//! "User's Username whoami::username(): {}", +//! whoami::username(), +//! ); +//! println!( +//! "User's Language whoami::lang(): {:?}", +//! whoami::lang().collect::>(), +//! ); +//! println!( +//! "Device's Pretty Name whoami::devicename(): {}", +//! whoami::devicename(), +//! ); +//! println!( +//! "Device's Hostname whoami::hostname(): {}", +//! whoami::hostname(), +//! ); +//! println!( +//! "Device's Platform whoami::platform(): {}", +//! whoami::platform(), +//! ); +//! println!( +//! "Device's OS Distro whoami::distro(): {}", +//! whoami::distro(), +//! ); +//! println!( +//! "Device's Desktop Env. whoami::desktop_env(): {}", +//! whoami::desktop_env(), +//! ); +//! println!( +//! "Device's CPU Arch whoami::arch(): {}", +//! whoami::arch(), +//! ); +//! ``` + +#![warn( + anonymous_parameters, + missing_copy_implementations, + missing_debug_implementations, + missing_docs, + nonstandard_style, + rust_2018_idioms, + single_use_lifetimes, + trivial_casts, + trivial_numeric_casts, + unreachable_pub, + unused_extern_crates, + unused_qualifications, + variant_size_differences, + unsafe_code +)] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg", + html_favicon_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg" +)] + +const DEFAULT_USERNAME: &str = "Unknown"; +const DEFAULT_HOSTNAME: &str = "LocalHost"; + +pub mod fallible; +pub mod disp; + +#[allow(unsafe_code)] +// Unix +#[cfg_attr( + not(any(target_os = "windows", target_arch = "wasm32")), + path = "unix.rs" +)] +// Wasm32 (Daku) - FIXME: Currently routes to fake.rs +#[cfg_attr(all(target_arch = "wasm32", target_os = "daku"), path = "fake.rs")] +// Wasm32 (Wasi) - FIXME: Currently routes to fake.rs +#[cfg_attr(all(target_arch = "wasm32", target_os = "wasi"), path = "fake.rs")] +// Wasm32 (Web) +#[cfg_attr( + all( + target_arch = "wasm32", + not(target_os = "wasi"), + not(target_os = "daku"), + feature = "web", + ), + path = "web.rs" +)] +// Wasm32 (Unknown) +#[cfg_attr( + all( + target_arch = "wasm32", + not(target_os = "wasi"), + not(target_os = "daku"), + not(feature = "web"), + ), + path = "fake.rs" +)] +// Windows +#[cfg_attr( + all(target_os = "windows", not(target_arch = "wasm32")), + path = "windows.rs" +)] +mod platform; + +use std::{ + ffi::OsString, + fmt::{self, Display, Formatter}, + io::{Error, ErrorKind}, +}; + +/// This crate's convenience type alias for [`Result`](std::result::Result)s +pub type Result = std::result::Result; + +/// Region code for a [`Language`] dialect +/// +/// Uses +#[non_exhaustive] +#[repr(u32)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum Region { + // FIXME: V2: u32::from_ne_bytes for region codes, with `\0` for unused + // FIXME: Add aliases up to 3-4 letters, but hidden + /// Any dialect + Any, + /// `US`: United States of America + #[doc(hidden)] + Us, +} + +impl Display for Region { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Any => "**", + Self::Us => "US", + }) + } +} + +/// A spoken language +/// +/// Use [`ToString::to_string()`] to convert to string of two letter lowercase +/// language code followed and underscore and uppercase region code (example: +/// `en_US`). +/// +/// Uses +#[non_exhaustive] +#[derive(Clone, Eq, PartialEq, Debug)] +// #[allow(variant_size_differences)] +pub enum Language { + #[doc(hidden)] + __(Box), + /// `en`: English + #[doc(hidden)] + En(Region), + /// `es`: Spanish + #[doc(hidden)] + Es(Region), +} + +impl Language { + /// Retrieve the region code for this language dialect. + pub fn region(&self) -> Region { + match self { + Self::__(_) => Region::Any, + Self::En(region) | Self::Es(region) => *region, + } + } +} + +impl Display for Language { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::__(code) => f.write_str(code.as_str()), + Self::En(region) => { + if *region != Region::Any { + f.write_str("en_")?; + ::fmt(region, f) + } else { + f.write_str("en") + } + } + Self::Es(region) => { + if *region != Region::Any { + f.write_str("es_")?; + ::fmt(region, f) + } else { + f.write_str("es") + } + } + } + } +} + +// FIXME: V2: Move `Unknown` variants to the top of the enum. + +/// The desktop environment of a system +#[derive(Debug, PartialEq, Eq, Clone)] +#[non_exhaustive] +pub enum DesktopEnv { + /// Popular GTK-based desktop environment on Linux + Gnome, + /// One of the desktop environments for a specific version of Windows + Windows, + /// Linux desktop environment optimized for low resource requirements + Lxde, + /// Stacking window manager for X Windows on Linux + Openbox, + /// Desktop environment for Linux, BSD and Illumos + Mate, + /// Lightweight desktop enivornment for unix-like operating systems + Xfce, + /// KDE Plasma desktop enviroment + // FIXME: Rename to 'Plasma' in whoami 2.0.0 + Kde, + /// Default desktop environment on Linux Mint + Cinnamon, + /// Tiling window manager for Linux + I3, + /// Desktop environment for MacOS + Aqua, + /// Desktop environment for iOS + Ios, + /// Desktop environment for Android + Android, + /// Running as Web Assembly on a web page + WebBrowser, + /// A desktop environment for a video game console + Console, + /// Ubuntu-branded GNOME + Ubuntu, + /// Default shell for Fuchsia + Ermine, + /// Default desktop environment for Redox + Orbital, + /// Unknown desktop environment + Unknown(String), +} + +impl Display for DesktopEnv { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Self::Unknown(_) = self { + f.write_str("Unknown: ")?; + } + + f.write_str(match self { + Self::Gnome => "Gnome", + Self::Windows => "Windows", + Self::Lxde => "LXDE", + Self::Openbox => "Openbox", + Self::Mate => "Mate", + Self::Xfce => "XFCE", + Self::Kde => "KDE", + Self::Cinnamon => "Cinnamon", + Self::I3 => "I3", + Self::Aqua => "Aqua", + Self::Ios => "IOS", + Self::Android => "Android", + Self::WebBrowser => "Web Browser", + Self::Console => "Console", + Self::Ubuntu => "Ubuntu", + Self::Ermine => "Ermine", + Self::Orbital => "Orbital", + Self::Unknown(a) => a, + }) + } +} + +/// The underlying platform for a system +#[allow(missing_docs)] +#[derive(Debug, PartialEq, Eq, Clone)] +#[non_exhaustive] +pub enum Platform { + Linux, + Bsd, + Windows, + // FIXME: Non-standard casing; Rename to 'Mac' rather than 'MacOs' in + // whoami 2.0.0 + MacOS, + Illumos, + Ios, + Android, + Nintendo, + Xbox, + PlayStation, + Fuchsia, + Redox, + Unknown(String), +} + +impl Display for Platform { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Self::Unknown(_) = self { + f.write_str("Unknown: ")?; + } + + f.write_str(match self { + Self::Linux => disp::display_linux(), + Self::Bsd => disp::display_bsd(), + Self::Windows => disp::display_windows(), + Self::MacOS => disp::display_macos(), + Self::Illumos => disp::display_illumos(), + Self::Ios => disp::display_ios(), + Self::Android => disp::display_android(), + Self::Nintendo => disp::display_nintendo(), + Self::Xbox => disp::display_xbox(), + Self::PlayStation => disp::display_playstation(), + Self::Fuchsia => disp::display_fuchsia(), + Self::Redox => disp::display_redox(), + Self::Unknown(a) => a, + }) + } +} + +/// The architecture of a CPU +#[non_exhaustive] +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Arch { + /// ARMv5 + ArmV5, + /// ARMv6 (Sometimes just referred to as ARM) + ArmV6, + /// ARMv7 (May or may not support Neon/Thumb) + ArmV7, + /// ARM64 (aarch64) + Arm64, + /// i386 (x86) + I386, + /// i586 (x86) + I586, + /// i686 (x86) + I686, + /// X86_64 / Amd64 + X64, + /// MIPS + Mips, + /// MIPS (LE) + MipsEl, + /// MIPS64 + Mips64, + /// MIPS64 (LE) + Mips64El, + /// PowerPC + PowerPc, + /// PowerPC64 + PowerPc64, + /// PowerPC64LE + PowerPc64Le, + /// 32-bit RISC-V + Riscv32, + /// 64-bit RISC-V + Riscv64, + /// S390x + S390x, + /// SPARC + Sparc, + /// SPARC64 + Sparc64, + /// 32-bit Web Assembly + Wasm32, + /// 64-bit Web Assembly + Wasm64, + /// Unknown Architecture + Unknown(String), +} + +impl Display for Arch { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Self::Unknown(_) = self { + f.write_str("Unknown: ")?; + } + + f.write_str(match self { + Self::ArmV5 => "armv5", + Self::ArmV6 => "armv6", + Self::ArmV7 => "armv7", + Self::Arm64 => "arm64", + Self::I386 => "i386", + Self::I586 => "i586", + Self::I686 => "i686", + Self::Mips => "mips", + Self::MipsEl => "mipsel", + Self::Mips64 => "mips64", + Self::Mips64El => "mips64el", + Self::PowerPc => "powerpc", + Self::PowerPc64 => "powerpc64", + Self::PowerPc64Le => "powerpc64le", + Self::Riscv32 => "riscv32", + Self::Riscv64 => "riscv64", + Self::S390x => "s390x", + Self::Sparc => "sparc", + Self::Sparc64 => "sparc64", + Self::Wasm32 => "wasm32", + Self::Wasm64 => "wasm64", + Self::X64 => "x86_64", + Self::Unknown(arch) => arch, + }) + } +} + +/// The address width of a CPU architecture +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[non_exhaustive] +pub enum Width { + /// 32 bits + Bits32, + /// 64 bits + Bits64, +} + +impl Display for Width { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Width::Bits32 => "32 bits", + Width::Bits64 => "64 bits", + }) + } +} + +impl Arch { + /// Get the width of this architecture. + pub fn width(&self) -> Result { + match self { + Arch::ArmV5 + | Arch::ArmV6 + | Arch::ArmV7 + | Arch::I386 + | Arch::I586 + | Arch::I686 + | Arch::Mips + | Arch::MipsEl + | Arch::PowerPc + | Arch::Riscv32 + | Arch::Sparc + | Arch::Wasm32 => Ok(Width::Bits32), + Arch::Arm64 + | Arch::Mips64 + | Arch::Mips64El + | Arch::PowerPc64 + | Arch::PowerPc64Le + | Arch::Riscv64 + | Arch::S390x + | Arch::Sparc64 + | Arch::Wasm64 + | Arch::X64 => Ok(Width::Bits64), + Arch::Unknown(unknown_arch) => Err(Error::new( + ErrorKind::InvalidData, + format!( + "Tried getting width of unknown arch ({})", + unknown_arch, + ), + )), + } + } +} + +/// Get the CPU Architecture. +#[inline(always)] +pub fn arch() -> Arch { + platform::arch() +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname()`] most notably in that spaces +/// are not allowed in the username. +#[inline(always)] +pub fn username() -> String { + fallible::username().unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase()) +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname_os()`] most notably in that +/// spaces are not allowed in the username. +#[inline(always)] +pub fn username_os() -> OsString { + fallible::username_os() + .unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase().into()) +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname() -> String { + fallible::realname() + .or_else(|_| fallible::username()) + .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned()) +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname_os() -> OsString { + fallible::realname_os() + .or_else(|_| fallible::username_os()) + .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into()) +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename() -> String { + fallible::devicename() + .or_else(|_| fallible::hostname()) + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string()) +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename_os() -> OsString { + fallible::devicename_os() + .or_else(|_| fallible::hostname_os()) + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into()) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname() -> String { + fallible::hostname().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase()) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname_os() -> OsString { + fallible::hostname_os() + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase().into()) +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro() -> String { + fallible::distro().unwrap_or_else(|_| format!("Unknown {}", platform())) +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro_os() -> OsString { + fallible::distro_os() + .unwrap_or_else(|_| format!("Unknown {}", platform()).into()) +} + +/// Get the desktop environment. +/// +/// Example: "gnome" or "windows" +#[inline(always)] +pub fn desktop_env() -> DesktopEnv { + platform::desktop_env() +} + +/// Get the platform. +#[inline(always)] +pub fn platform() -> Platform { + platform::platform() +} + +/// Get the user's preferred language(s). +/// +/// Returned as iterator of two letter language codes (lowercase), optionally +/// followed by a dash (-) and a two letter region code (uppercase). The most +/// preferred language is returned first, followed by next preferred, and so on. +#[inline(always)] +#[deprecated(note = "use `langs()` instead", since = "1.5.0")] +pub fn lang() -> impl Iterator { + platform::lang() +} + +/// Get the user's preferred language(s). +/// +/// Returned as iterator of [`Language`]s wrapped in [`Result`]s. The most +/// preferred language is returned first, followed by next preferred, and so on. +/// Unrecognized languages may return an error. +#[inline(always)] +pub fn langs() -> impl Iterator> { + #[allow(deprecated)] + lang().map(|string| Ok(Language::__(Box::new(string)))) +} diff --git a/src/unix.rs b/src/unix.rs index 99cdcc8..3f867c7 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -1,681 +1,681 @@ -use std::{ - borrow::Cow, - ffi::{c_void, CStr, OsString}, - io::{Error, ErrorKind}, - mem, - os::{ - raw::{c_char, c_int}, - unix::ffi::OsStringExt, - }, -}; -#[cfg(target_os = "macos")] -use std::{ - os::{ - raw::{c_long, c_uchar}, - unix::ffi::OsStrExt, - }, - ptr::null_mut, -}; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[repr(C)] -struct PassWd { - pw_name: *const c_void, - pw_passwd: *const c_void, - pw_uid: u32, - pw_gid: u32, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_change: isize, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_class: *const c_void, - pw_gecos: *const c_void, - pw_dir: *const c_void, - pw_shell: *const c_void, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_expire: isize, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_fields: i32, -} - -extern "system" { - fn getpwuid_r( - uid: u32, - pwd: *mut PassWd, - buf: *mut c_void, - buflen: usize, - result: *mut *mut PassWd, - ) -> i32; - fn geteuid() -> u32; - fn gethostname(name: *mut c_void, len: usize) -> i32; -} - -#[cfg(target_os = "macos")] -#[link(name = "CoreFoundation", kind = "framework")] -#[link(name = "SystemConfiguration", kind = "framework")] -extern "system" { - fn CFStringGetCString( - the_string: *mut c_void, - buffer: *mut u8, - buffer_size: c_long, - encoding: u32, - ) -> c_uchar; - fn CFStringGetLength(the_string: *mut c_void) -> c_long; - fn CFStringGetMaximumSizeForEncoding( - length: c_long, - encoding: u32, - ) -> c_long; - fn SCDynamicStoreCopyComputerName( - store: *mut c_void, - encoding: *mut u32, - ) -> *mut c_void; - fn CFRelease(cf: *const c_void); -} - -unsafe fn strlen(cs: *const c_void) -> usize { - let mut len = 0; - let mut cs: *const u8 = cs.cast(); - while *cs != 0 { - len += 1; - cs = cs.offset(1); - } - len -} - -unsafe fn strlen_gecos(cs: *const c_void) -> usize { - let mut len = 0; - let mut cs: *const u8 = cs.cast(); - while *cs != 0 && *cs != b',' { - len += 1; - cs = cs.offset(1); - } - len -} - -// Convert an OsString into a String -fn string_from_os(string: OsString) -> String { - match string.into_string() { - Ok(string) => string, - Err(string) => string.to_string_lossy().to_string(), - } -} - -fn os_from_cstring_gecos(string: *const c_void) -> Result { - if string.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - // Get a byte slice of the c string. - let slice = unsafe { - let length = strlen_gecos(string); - - if length == 0 { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - std::slice::from_raw_parts(string.cast(), length) - }; - - // Turn byte slice into Rust String. - Ok(OsString::from_vec(slice.to_vec())) -} - -fn os_from_cstring(string: *const c_void) -> Result { - if string.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - // Get a byte slice of the c string. - let slice = unsafe { - let length = strlen(string); - - if length == 0 { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - std::slice::from_raw_parts(string.cast(), length) - }; - - // Turn byte slice into Rust String. - Ok(OsString::from_vec(slice.to_vec())) -} - -#[cfg(target_os = "macos")] -fn os_from_cfstring(string: *mut c_void) -> OsString { - if string.is_null() { - return "".to_string().into(); - } - - unsafe { - let len = CFStringGetLength(string); - let capacity = - CFStringGetMaximumSizeForEncoding(len, 134_217_984 /* UTF8 */) + 1; - let mut out = Vec::with_capacity(capacity as usize); - if CFStringGetCString( - string, - out.as_mut_ptr(), - capacity, - 134_217_984, /* UTF8 */ - ) != 0 - { - out.set_len(strlen(out.as_ptr().cast())); // Remove trailing NUL byte - out.shrink_to_fit(); - CFRelease(string); - OsString::from_vec(out) - } else { - CFRelease(string); - "".to_string().into() - } - } -} - -// This function must allocate, because a slice or Cow would still -// reference `passwd` which is dropped when this function returns. -#[inline(always)] -fn getpwuid(real: bool) -> Result { - const BUF_SIZE: usize = 16_384; // size from the man page - let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit(); - let mut passwd = mem::MaybeUninit::::uninit(); - let mut _passwd = mem::MaybeUninit::<*mut PassWd>::uninit(); - - // Get PassWd `struct`. - let passwd = unsafe { - let ret = getpwuid_r( - geteuid(), - passwd.as_mut_ptr(), - buffer.as_mut_ptr() as *mut c_void, - BUF_SIZE, - _passwd.as_mut_ptr(), - ); - - if ret != 0 { - return Err(Error::last_os_error()); - } - - let _passwd = _passwd.assume_init(); - - if _passwd.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - passwd.assume_init() - }; - - // Extract names. - if real { - os_from_cstring_gecos(passwd.pw_gecos) - } else { - os_from_cstring(passwd.pw_name) - } -} - -pub(crate) fn username() -> Result { - Ok(string_from_os(username_os()?)) -} - -pub(crate) fn username_os() -> Result { - getpwuid(false) -} - -pub(crate) fn realname() -> Result { - Ok(string_from_os(realname_os()?)) -} - -pub(crate) fn realname_os() -> Result { - getpwuid(true) -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[cfg(not(any(target_os = "macos", target_os = "illumos")))] -pub(crate) fn devicename() -> Result { - let machine_info = std::fs::read("/etc/machine-info")?; - let machine_info = String::from_utf8_lossy(&machine_info); - - for i in machine_info.split('\n') { - let mut j = i.split('='); - - if j.next() == Some("PRETTY_HOSTNAME") { - if let Some(value) = j.next() { - // FIXME: Can " be escaped in pretty name? - return Ok(value.trim_matches('"').to_string()); - } - } - } - - Err(Error::new(ErrorKind::NotFound, "Missing record")) -} - -#[cfg(target_os = "macos")] -pub(crate) fn devicename() -> Result { - Ok(string_from_os(devicename_os()?)) -} - -#[cfg(target_os = "macos")] -pub(crate) fn devicename_os() -> Result { - let out = os_from_cfstring(unsafe { - SCDynamicStoreCopyComputerName(null_mut(), null_mut()) - }); - - if out.as_bytes().is_empty() { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - Ok(out) -} - -#[cfg(target_os = "illumos")] -pub(crate) fn devicename() -> Result { - let program = std::fs::read("/etc/nodename")?; - let mut nodename = String::from_utf8_lossy(&program).to_string(); - // Remove the trailing newline - let _ = nodename.pop(); - - if nodename.is_empty() { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - Ok(nodename) -} - -pub(crate) fn hostname() -> Result { - Ok(string_from_os(hostname_os()?)) -} - -fn hostname_os() -> Result { - // Maximum hostname length = 255, plus a NULL byte. - let mut string = Vec::::with_capacity(256); - - unsafe { - if gethostname(string.as_mut_ptr() as *mut c_void, 255) == -1 { - return Err(Error::last_os_error()); - } - - string.set_len(strlen(string.as_ptr() as *const c_void)); - }; - - Ok(OsString::from_vec(string)) -} - -#[cfg(target_os = "macos")] -fn distro_xml(data: String) -> Result { - let mut product_name = None; - let mut user_visible_version = None; - - if let Some(start) = data.find("") { - if let Some(end) = data.find("") { - let mut set_product_name = false; - let mut set_user_visible_version = false; - - for line in data[start + "".len()..end].lines() { - let line = line.trim(); - - if line.starts_with("") { - match line["".len()..].trim_end_matches("") { - "ProductName" => set_product_name = true, - "ProductUserVisibleVersion" => { - set_user_visible_version = true - } - "ProductVersion" => { - if user_visible_version.is_none() { - set_user_visible_version = true - } - } - _ => {} - } - } else if line.starts_with("") { - if set_product_name { - product_name = Some( - line["".len()..] - .trim_end_matches(""), - ); - set_product_name = false; - } else if set_user_visible_version { - user_visible_version = Some( - line["".len()..] - .trim_end_matches(""), - ); - set_user_visible_version = false; - } - } - } - } - } - - Ok(if let Some(product_name) = product_name { - if let Some(user_visible_version) = user_visible_version { - format!("{} {}", product_name, user_visible_version) - } else { - product_name.to_string() - } - } else { - user_visible_version - .map(|v| format!("Mac OS (Unknown) {}", v)) - .ok_or_else(|| { - Error::new(ErrorKind::InvalidData, "Parsing failed") - })? - }) -} - -#[cfg(target_os = "macos")] -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -#[cfg(target_os = "macos")] -pub(crate) fn distro() -> Result { - if let Ok(data) = std::fs::read_to_string( - "/System/Library/CoreServices/ServerVersion.plist", - ) { - distro_xml(data) - } else if let Ok(data) = std::fs::read_to_string( - "/System/Library/CoreServices/SystemVersion.plist", - ) { - distro_xml(data) - } else { - Err(Error::new(ErrorKind::NotFound, "Missing record")) - } -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn distro() -> Result { - let program = std::fs::read("/etc/os-release")?; - let distro = String::from_utf8_lossy(&program); - let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); - let mut fallback = None; - - for i in distro.split('\n') { - let mut j = i.split('='); - - match j.next().ok_or_else(err)? { - "PRETTY_NAME" => { - return Ok(j - .next() - .ok_or_else(err)? - .trim_matches('"') - .to_string()); - } - "NAME" => { - fallback = Some( - j.next().ok_or_else(err)?.trim_matches('"').to_string(), - ) - } - _ => {} - } - } - - fallback.ok_or_else(err) -} - -#[cfg(target_os = "macos")] -#[inline(always)] -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::Aqua -} - -#[cfg(not(target_os = "macos"))] -#[inline(always)] -pub(crate) fn desktop_env() -> DesktopEnv { - match std::env::var_os("DESKTOP_SESSION") - .map(|env| env.to_string_lossy().to_string()) - { - Some(env_orig) => { - let env = env_orig.to_uppercase(); - - if env.contains("GNOME") { - DesktopEnv::Gnome - } else if env.contains("LXDE") { - DesktopEnv::Lxde - } else if env.contains("OPENBOX") { - DesktopEnv::Openbox - } else if env.contains("I3") { - DesktopEnv::I3 - } else if env.contains("UBUNTU") { - DesktopEnv::Ubuntu - } else if env.contains("PLASMA5") { - DesktopEnv::Kde - } else { - DesktopEnv::Unknown(env_orig) - } - } - // TODO: Other Linux Desktop Environments - None => DesktopEnv::Unknown("Unknown".to_string()), - } -} - -#[cfg(target_os = "macos")] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::MacOS -} - -#[cfg(not(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd", - target_os = "illumos" -)))] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Linux -} - -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" -))] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Bsd -} - -#[cfg(target_os = "illumos")] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Illumos -} - -struct LangIter { - array: String, - index: Option, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if self.index? && self.array.contains('-') { - self.index = Some(false); - let mut temp = self.array.split('-').next()?.to_string(); - mem::swap(&mut temp, &mut self.array); - Some(temp) - } else { - self.index = None; - let mut temp = String::new(); - mem::swap(&mut temp, &mut self.array); - Some(temp) - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - const DEFAULT_LANG: &str = "en_US"; - - let array = std::env::var("LANG") - .unwrap_or_default() - .split('.') - .next() - .unwrap_or(DEFAULT_LANG) - .to_string(); - let array = if array == "C" { - DEFAULT_LANG.to_string() - } else { - array - }; - - LangIter { - array: array.replace('_', "-"), - index: Some(true), - } -} - -#[repr(C)] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos" -))] -struct UtsName { - #[cfg(not(target_os = "dragonfly"))] - sysname: [c_char; 256], - #[cfg(target_os = "dragonfly")] - sysname: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - nodename: [c_char; 256], - #[cfg(target_os = "dragonfly")] - nodename: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - release: [c_char; 256], - #[cfg(target_os = "dragonfly")] - release: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - version: [c_char; 256], - #[cfg(target_os = "dragonfly")] - version: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - machine: [c_char; 256], - #[cfg(target_os = "dragonfly")] - machine: [c_char; 32], -} - -#[repr(C)] -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "redox" -))] -struct UtsName { - sysname: [c_char; 65], - nodename: [c_char; 65], - release: [c_char; 65], - version: [c_char; 65], - machine: [c_char; 65], - domainname: [c_char; 65], -} - -// Buffer initialization -impl Default for UtsName { - fn default() -> Self { - unsafe { mem::zeroed() } - } -} - -extern "C" { - #[cfg(not(target_os = "freebsd"))] - fn uname(buf: *mut UtsName) -> c_int; - - #[cfg(target_os = "freebsd")] - fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; -} -#[inline] -#[cfg(target_os = "freebsd")] -unsafe extern "C" fn uname(buf: *mut UtsName) -> c_int { - __xuname(256, buf.cast()) -} - -impl Arch { - fn from_str(s: Cow<'_, str>) -> Self { - let arch_str = match s { - Cow::Borrowed(str) => str, - Cow::Owned(ref str) => str, - }; - match arch_str { - "aarch64" | "arm64" | "aarch64_be" | "armv8b" | "armv8l" => { - Arch::Arm64 - } - "armv5" => Arch::ArmV5, - "armv6" | "arm" => Arch::ArmV6, - "armv7" => Arch::ArmV7, - "i386" => Arch::I386, - "i586" => Arch::I586, - "i686" | "i686-AT386" => Arch::I686, - "mips" => Arch::Mips, - "mipsel" => Arch::MipsEl, - "mips64" => Arch::Mips64, - "mips64el" => Arch::Mips64El, - "powerpc" | "ppc" | "ppcle" => Arch::PowerPc, - "powerpc64" | "ppc64" | "ppc64le" => Arch::PowerPc64, - "powerpc64le" => Arch::PowerPc64Le, - "riscv32" => Arch::Riscv32, - "riscv64" => Arch::Riscv64, - "s390x" => Arch::S390x, - "sparc" => Arch::Sparc, - "sparc64" => Arch::Sparc64, - "wasm32" => Arch::Wasm32, - "wasm64" => Arch::Wasm64, - "x86_64" | "amd64" => Arch::X64, - _ => Arch::Unknown(arch_str.to_owned()), - } - } -} - -pub(crate) fn arch() -> Arch { - let mut buf = UtsName::default(); - let result = unsafe { uname(&mut buf) }; - if result == -1 { - return Arch::Unknown("uname(2) failed to execute".to_owned()); - } - - let arch_str = - unsafe { CStr::from_ptr(buf.machine.as_ptr()) }.to_string_lossy(); - - Arch::from_str(arch_str) -} +use std::{ + borrow::Cow, + ffi::{c_void, CStr, OsString}, + io::{Error, ErrorKind}, + mem, + os::{ + raw::{c_char, c_int}, + unix::ffi::OsStringExt, + }, +}; +#[cfg(target_os = "macos")] +use std::{ + os::{ + raw::{c_long, c_uchar}, + unix::ffi::OsStrExt, + }, + ptr::null_mut, +}; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[repr(C)] +struct PassWd { + pw_name: *const c_void, + pw_passwd: *const c_void, + pw_uid: u32, + pw_gid: u32, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_change: isize, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_class: *const c_void, + pw_gecos: *const c_void, + pw_dir: *const c_void, + pw_shell: *const c_void, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_expire: isize, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_fields: i32, +} + +extern "system" { + fn getpwuid_r( + uid: u32, + pwd: *mut PassWd, + buf: *mut c_void, + buflen: usize, + result: *mut *mut PassWd, + ) -> i32; + fn geteuid() -> u32; + fn gethostname(name: *mut c_void, len: usize) -> i32; +} + +#[cfg(target_os = "macos")] +#[link(name = "CoreFoundation", kind = "framework")] +#[link(name = "SystemConfiguration", kind = "framework")] +extern "system" { + fn CFStringGetCString( + the_string: *mut c_void, + buffer: *mut u8, + buffer_size: c_long, + encoding: u32, + ) -> c_uchar; + fn CFStringGetLength(the_string: *mut c_void) -> c_long; + fn CFStringGetMaximumSizeForEncoding( + length: c_long, + encoding: u32, + ) -> c_long; + fn SCDynamicStoreCopyComputerName( + store: *mut c_void, + encoding: *mut u32, + ) -> *mut c_void; + fn CFRelease(cf: *const c_void); +} + +unsafe fn strlen(cs: *const c_void) -> usize { + let mut len = 0; + let mut cs: *const u8 = cs.cast(); + while *cs != 0 { + len += 1; + cs = cs.offset(1); + } + len +} + +unsafe fn strlen_gecos(cs: *const c_void) -> usize { + let mut len = 0; + let mut cs: *const u8 = cs.cast(); + while *cs != 0 && *cs != b',' { + len += 1; + cs = cs.offset(1); + } + len +} + +// Convert an OsString into a String +fn string_from_os(string: OsString) -> String { + match string.into_string() { + Ok(string) => string, + Err(string) => string.to_string_lossy().to_string(), + } +} + +fn os_from_cstring_gecos(string: *const c_void) -> Result { + if string.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + // Get a byte slice of the c string. + let slice = unsafe { + let length = strlen_gecos(string); + + if length == 0 { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + std::slice::from_raw_parts(string.cast(), length) + }; + + // Turn byte slice into Rust String. + Ok(OsString::from_vec(slice.to_vec())) +} + +fn os_from_cstring(string: *const c_void) -> Result { + if string.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + // Get a byte slice of the c string. + let slice = unsafe { + let length = strlen(string); + + if length == 0 { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + std::slice::from_raw_parts(string.cast(), length) + }; + + // Turn byte slice into Rust String. + Ok(OsString::from_vec(slice.to_vec())) +} + +#[cfg(target_os = "macos")] +fn os_from_cfstring(string: *mut c_void) -> OsString { + if string.is_null() { + return "".to_string().into(); + } + + unsafe { + let len = CFStringGetLength(string); + let capacity = + CFStringGetMaximumSizeForEncoding(len, 134_217_984 /* UTF8 */) + 1; + let mut out = Vec::with_capacity(capacity as usize); + if CFStringGetCString( + string, + out.as_mut_ptr(), + capacity, + 134_217_984, /* UTF8 */ + ) != 0 + { + out.set_len(strlen(out.as_ptr().cast())); // Remove trailing NUL byte + out.shrink_to_fit(); + CFRelease(string); + OsString::from_vec(out) + } else { + CFRelease(string); + "".to_string().into() + } + } +} + +// This function must allocate, because a slice or Cow would still +// reference `passwd` which is dropped when this function returns. +#[inline(always)] +fn getpwuid(real: bool) -> Result { + const BUF_SIZE: usize = 16_384; // size from the man page + let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit(); + let mut passwd = mem::MaybeUninit::::uninit(); + let mut _passwd = mem::MaybeUninit::<*mut PassWd>::uninit(); + + // Get PassWd `struct`. + let passwd = unsafe { + let ret = getpwuid_r( + geteuid(), + passwd.as_mut_ptr(), + buffer.as_mut_ptr() as *mut c_void, + BUF_SIZE, + _passwd.as_mut_ptr(), + ); + + if ret != 0 { + return Err(Error::last_os_error()); + } + + let _passwd = _passwd.assume_init(); + + if _passwd.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + passwd.assume_init() + }; + + // Extract names. + if real { + os_from_cstring_gecos(passwd.pw_gecos) + } else { + os_from_cstring(passwd.pw_name) + } +} + +pub(crate) fn username() -> Result { + Ok(string_from_os(username_os()?)) +} + +pub(crate) fn username_os() -> Result { + getpwuid(false) +} + +pub(crate) fn realname() -> Result { + Ok(string_from_os(realname_os()?)) +} + +pub(crate) fn realname_os() -> Result { + getpwuid(true) +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[cfg(not(any(target_os = "macos", target_os = "illumos")))] +pub(crate) fn devicename() -> Result { + let machine_info = std::fs::read("/etc/machine-info")?; + let machine_info = String::from_utf8_lossy(&machine_info); + + for i in machine_info.split('\n') { + let mut j = i.split('='); + + if j.next() == Some("PRETTY_HOSTNAME") { + if let Some(value) = j.next() { + // FIXME: Can " be escaped in pretty name? + return Ok(value.trim_matches('"').to_string()); + } + } + } + + Err(Error::new(ErrorKind::NotFound, "Missing record")) +} + +#[cfg(target_os = "macos")] +pub(crate) fn devicename() -> Result { + Ok(string_from_os(devicename_os()?)) +} + +#[cfg(target_os = "macos")] +pub(crate) fn devicename_os() -> Result { + let out = os_from_cfstring(unsafe { + SCDynamicStoreCopyComputerName(null_mut(), null_mut()) + }); + + if out.as_bytes().is_empty() { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + Ok(out) +} + +#[cfg(target_os = "illumos")] +pub(crate) fn devicename() -> Result { + let program = std::fs::read("/etc/nodename")?; + let mut nodename = String::from_utf8_lossy(&program).to_string(); + // Remove the trailing newline + let _ = nodename.pop(); + + if nodename.is_empty() { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + Ok(nodename) +} + +pub(crate) fn hostname() -> Result { + Ok(string_from_os(hostname_os()?)) +} + +fn hostname_os() -> Result { + // Maximum hostname length = 255, plus a NULL byte. + let mut string = Vec::::with_capacity(256); + + unsafe { + if gethostname(string.as_mut_ptr() as *mut c_void, 255) == -1 { + return Err(Error::last_os_error()); + } + + string.set_len(strlen(string.as_ptr() as *const c_void)); + }; + + Ok(OsString::from_vec(string)) +} + +#[cfg(target_os = "macos")] +fn distro_xml(data: String) -> Result { + let mut product_name = None; + let mut user_visible_version = None; + + if let Some(start) = data.find("") { + if let Some(end) = data.find("") { + let mut set_product_name = false; + let mut set_user_visible_version = false; + + for line in data[start + "".len()..end].lines() { + let line = line.trim(); + + if line.starts_with("") { + match line["".len()..].trim_end_matches("") { + "ProductName" => set_product_name = true, + "ProductUserVisibleVersion" => { + set_user_visible_version = true + } + "ProductVersion" => { + if user_visible_version.is_none() { + set_user_visible_version = true + } + } + _ => {} + } + } else if line.starts_with("") { + if set_product_name { + product_name = Some( + line["".len()..] + .trim_end_matches(""), + ); + set_product_name = false; + } else if set_user_visible_version { + user_visible_version = Some( + line["".len()..] + .trim_end_matches(""), + ); + set_user_visible_version = false; + } + } + } + } + } + + Ok(if let Some(product_name) = product_name { + if let Some(user_visible_version) = user_visible_version { + format!("{} {}", product_name, user_visible_version) + } else { + product_name.to_string() + } + } else { + user_visible_version + .map(|v| format!("Mac OS (Unknown) {}", v)) + .ok_or_else(|| { + Error::new(ErrorKind::InvalidData, "Parsing failed") + })? + }) +} + +#[cfg(target_os = "macos")] +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +#[cfg(target_os = "macos")] +pub(crate) fn distro() -> Result { + if let Ok(data) = std::fs::read_to_string( + "/System/Library/CoreServices/ServerVersion.plist", + ) { + distro_xml(data) + } else if let Ok(data) = std::fs::read_to_string( + "/System/Library/CoreServices/SystemVersion.plist", + ) { + distro_xml(data) + } else { + Err(Error::new(ErrorKind::NotFound, "Missing record")) + } +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn distro() -> Result { + let program = std::fs::read("/etc/os-release")?; + let distro = String::from_utf8_lossy(&program); + let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); + let mut fallback = None; + + for i in distro.split('\n') { + let mut j = i.split('='); + + match j.next().ok_or_else(err)? { + "PRETTY_NAME" => { + return Ok(j + .next() + .ok_or_else(err)? + .trim_matches('"') + .to_string()); + } + "NAME" => { + fallback = Some( + j.next().ok_or_else(err)?.trim_matches('"').to_string(), + ) + } + _ => {} + } + } + + fallback.ok_or_else(err) +} + +#[cfg(target_os = "macos")] +#[inline(always)] +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::Aqua +} + +#[cfg(not(target_os = "macos"))] +#[inline(always)] +pub(crate) fn desktop_env() -> DesktopEnv { + match std::env::var_os("DESKTOP_SESSION") + .map(|env| env.to_string_lossy().to_string()) + { + Some(env_orig) => { + let env = env_orig.to_uppercase(); + + if env.contains("GNOME") { + DesktopEnv::Gnome + } else if env.contains("LXDE") { + DesktopEnv::Lxde + } else if env.contains("OPENBOX") { + DesktopEnv::Openbox + } else if env.contains("I3") { + DesktopEnv::I3 + } else if env.contains("UBUNTU") { + DesktopEnv::Ubuntu + } else if env.contains("PLASMA5") { + DesktopEnv::Kde + } else { + DesktopEnv::Unknown(env_orig) + } + } + // TODO: Other Linux Desktop Environments + None => DesktopEnv::Unknown("Unknown".to_string()), + } +} + +#[cfg(target_os = "macos")] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::MacOS +} + +#[cfg(not(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd", + target_os = "illumos" +)))] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Linux +} + +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" +))] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Bsd +} + +#[cfg(target_os = "illumos")] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Illumos +} + +struct LangIter { + array: String, + index: Option, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if self.index? && self.array.contains('-') { + self.index = Some(false); + let mut temp = self.array.split('-').next()?.to_string(); + mem::swap(&mut temp, &mut self.array); + Some(temp) + } else { + self.index = None; + let mut temp = String::new(); + mem::swap(&mut temp, &mut self.array); + Some(temp) + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + const DEFAULT_LANG: &str = "en_US"; + + let array = std::env::var("LANG") + .unwrap_or_default() + .split('.') + .next() + .unwrap_or(DEFAULT_LANG) + .to_string(); + let array = if array == "C" { + DEFAULT_LANG.to_string() + } else { + array + }; + + LangIter { + array: array.replace('_', "-"), + index: Some(true), + } +} + +#[repr(C)] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd", + target_os = "illumos" +))] +struct UtsName { + #[cfg(not(target_os = "dragonfly"))] + sysname: [c_char; 256], + #[cfg(target_os = "dragonfly")] + sysname: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + nodename: [c_char; 256], + #[cfg(target_os = "dragonfly")] + nodename: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + release: [c_char; 256], + #[cfg(target_os = "dragonfly")] + release: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + version: [c_char; 256], + #[cfg(target_os = "dragonfly")] + version: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + machine: [c_char; 256], + #[cfg(target_os = "dragonfly")] + machine: [c_char; 32], +} + +#[repr(C)] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "redox" +))] +struct UtsName { + sysname: [c_char; 65], + nodename: [c_char; 65], + release: [c_char; 65], + version: [c_char; 65], + machine: [c_char; 65], + domainname: [c_char; 65], +} + +// Buffer initialization +impl Default for UtsName { + fn default() -> Self { + unsafe { mem::zeroed() } + } +} + +extern "C" { + #[cfg(not(target_os = "freebsd"))] + fn uname(buf: *mut UtsName) -> c_int; + + #[cfg(target_os = "freebsd")] + fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; +} +#[inline] +#[cfg(target_os = "freebsd")] +unsafe extern "C" fn uname(buf: *mut UtsName) -> c_int { + __xuname(256, buf.cast()) +} + +impl Arch { + fn from_str(s: Cow<'_, str>) -> Self { + let arch_str = match s { + Cow::Borrowed(str) => str, + Cow::Owned(ref str) => str, + }; + match arch_str { + "aarch64" | "arm64" | "aarch64_be" | "armv8b" | "armv8l" => { + Arch::Arm64 + } + "armv5" => Arch::ArmV5, + "armv6" | "arm" => Arch::ArmV6, + "armv7" => Arch::ArmV7, + "i386" => Arch::I386, + "i586" => Arch::I586, + "i686" | "i686-AT386" => Arch::I686, + "mips" => Arch::Mips, + "mipsel" => Arch::MipsEl, + "mips64" => Arch::Mips64, + "mips64el" => Arch::Mips64El, + "powerpc" | "ppc" | "ppcle" => Arch::PowerPc, + "powerpc64" | "ppc64" | "ppc64le" => Arch::PowerPc64, + "powerpc64le" => Arch::PowerPc64Le, + "riscv32" => Arch::Riscv32, + "riscv64" => Arch::Riscv64, + "s390x" => Arch::S390x, + "sparc" => Arch::Sparc, + "sparc64" => Arch::Sparc64, + "wasm32" => Arch::Wasm32, + "wasm64" => Arch::Wasm64, + "x86_64" | "amd64" => Arch::X64, + _ => Arch::Unknown(arch_str.to_owned()), + } + } +} + +pub(crate) fn arch() -> Arch { + let mut buf = UtsName::default(); + let result = unsafe { uname(&mut buf) }; + if result == -1 { + return Arch::Unknown("uname(2) failed to execute".to_owned()); + } + + let arch_str = + unsafe { CStr::from_ptr(buf.machine.as_ptr()) }.to_string_lossy(); + + Arch::from_str(arch_str) +} diff --git a/src/web.rs b/src/web.rs index cf1f619..04f93e8 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,247 +1,247 @@ -#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] -compile_error!("Unexpected pointer width for target platform"); - -use std::{ - ffi::OsString, - io::{Error, ErrorKind}, -}; - -use wasm_bindgen::JsValue; -use web_sys::window; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -// Get the user agent -fn user_agent() -> Option { - window()?.navigator().user_agent().ok() -} - -// Get the document domain -fn document_domain() -> Option { - window()?.document()?.location()?.hostname().ok() -} - -struct LangIter { - array: Vec, - index: usize, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if let Some(value) = self.array.get(self.index) { - self.index += 1; - if let Some(lang) = value.as_string() { - Some(lang) - } else { - self.next() - } - } else { - None - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - let array = if let Some(window) = window() { - window.navigator().languages().to_vec() - } else { - Vec::new() - }; - let index = 0; - - LangIter { array, index } -} - -#[inline(always)] -pub(crate) fn username_os() -> Result { - Ok(username()?.into()) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - Ok(realname()?.into()) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[inline(always)] -pub(crate) fn distro_os() -> Result { - Ok(distro()?.into()) -} - -#[inline(always)] -pub(crate) fn username() -> Result { - Ok("anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok("Anonymous".to_string()) -} - -pub(crate) fn devicename() -> Result { - let orig_string = user_agent().unwrap_or_default(); - - let start = if let Some(s) = orig_string.rfind(' ') { - s - } else { - return Ok("Unknown Browser".to_string()); - }; - - let string = orig_string - .get(start + 1..) - .unwrap_or("Unknown Browser") - .replace('/', " "); - - Ok(if let Some(s) = string.rfind("Safari") { - if let Some(s) = orig_string.rfind("Chrome") { - if let Some(e) = orig_string.get(s..).unwrap_or_default().find(' ') - { - orig_string - .get(s..) - .unwrap_or("Chrome") - .get(..e) - .unwrap_or("Chrome") - .replace('/', " ") - } else { - "Chrome".to_string() - } - } else if orig_string.contains("Linux") { - "GNOME Web".to_string() - } else { - string.get(s..).unwrap_or("Safari").replace('/', " ") - } - } else if string.contains("Edg ") { - string.replace("Edg ", "Edge ") - } else if string.contains("OPR ") { - string.replace("OPR ", "Opera ") - } else { - string - }) -} - -#[inline(always)] -pub(crate) fn hostname() -> Result { - document_domain() - .filter(|x| !x.is_empty()) - .ok_or_else(|| Error::new(ErrorKind::NotFound, "Domain missing")) -} - -pub(crate) fn distro() -> Result { - let string = - user_agent().ok_or_else(|| Error::from(ErrorKind::PermissionDenied))?; - let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); - let begin = string.find('(').ok_or_else(err)?; - let end = string.find(')').ok_or_else(err)?; - let string = &string[begin + 1..end]; - - Ok(if string.contains("Win32") || string.contains("Win64") { - let begin = if let Some(b) = string.find("NT") { - b - } else { - return Ok("Windows".to_string()); - }; - let end = if let Some(e) = string.find('.') { - e - } else { - return Ok("Windows".to_string()); - }; - let string = &string[begin + 3..end]; - - format!("Windows {}", string) - } else if string.contains("Linux") { - let string = if string.contains("X11") || string.contains("Wayland") { - let begin = if let Some(b) = string.find(';') { - b - } else { - return Ok("Unknown Linux".to_string()); - }; - &string[begin + 2..] - } else { - string - }; - - if string.starts_with("Linux") { - "Unknown Linux".to_string() - } else { - let end = if let Some(e) = string.find(';') { - e - } else { - return Ok("Unknown Linux".to_string()); - }; - string[..end].to_string() - } - } else if let Some(begin) = string.find("Mac OS X") { - if let Some(end) = string[begin..].find(';') { - string[begin..begin + end].to_string() - } else { - string[begin..].to_string().replace('_', ".") - } - } else { - // TODO: - // Platform::FreeBsd, - // Platform::Ios, - // Platform::Android, - // Platform::Nintendo, - // Platform::Xbox, - // Platform::PlayStation, - // Platform::Dive, - // Platform::Fuchsia, - // Platform::Redox - string.to_string() - }) -} - -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::WebBrowser -} - -pub(crate) fn platform() -> Platform { - let string = user_agent().unwrap_or_default(); - - let begin = if let Some(b) = string.find('(') { - b - } else { - return Platform::Unknown("Unknown".to_string()); - }; - let end = if let Some(e) = string.find(')') { - e - } else { - return Platform::Unknown("Unknown".to_string()); - }; - let string = &string[begin + 1..end]; - - if string.contains("Win32") || string.contains("Win64") { - Platform::Windows - } else if string.contains("Linux") { - Platform::Linux - } else if string.contains("Mac OS X") { - Platform::MacOS - } else { - // TODO: - // Platform::FreeBsd, - // Platform::Ios, - // Platform::Android, - // Platform::Nintendo, - // Platform::Xbox, - // Platform::PlayStation, - // Platform::Dive, - // Platform::Fuchsia, - // Platform::Redox, - Platform::Unknown(string.to_string()) - } -} - -pub(crate) fn arch() -> Arch { - if cfg!(target_pointer_width = "64") { - Arch::Wasm64 - } else { - Arch::Wasm32 - } -} +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("Unexpected pointer width for target platform"); + +use std::{ + ffi::OsString, + io::{Error, ErrorKind}, +}; + +use wasm_bindgen::JsValue; +use web_sys::window; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +// Get the user agent +fn user_agent() -> Option { + window()?.navigator().user_agent().ok() +} + +// Get the document domain +fn document_domain() -> Option { + window()?.document()?.location()?.hostname().ok() +} + +struct LangIter { + array: Vec, + index: usize, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if let Some(value) = self.array.get(self.index) { + self.index += 1; + if let Some(lang) = value.as_string() { + Some(lang) + } else { + self.next() + } + } else { + None + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + let array = if let Some(window) = window() { + window.navigator().languages().to_vec() + } else { + Vec::new() + }; + let index = 0; + + LangIter { array, index } +} + +#[inline(always)] +pub(crate) fn username_os() -> Result { + Ok(username()?.into()) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + Ok(realname()?.into()) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[inline(always)] +pub(crate) fn distro_os() -> Result { + Ok(distro()?.into()) +} + +#[inline(always)] +pub(crate) fn username() -> Result { + Ok("anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok("Anonymous".to_string()) +} + +pub(crate) fn devicename() -> Result { + let orig_string = user_agent().unwrap_or_default(); + + let start = if let Some(s) = orig_string.rfind(' ') { + s + } else { + return Ok("Unknown Browser".to_string()); + }; + + let string = orig_string + .get(start + 1..) + .unwrap_or("Unknown Browser") + .replace('/', " "); + + Ok(if let Some(s) = string.rfind("Safari") { + if let Some(s) = orig_string.rfind("Chrome") { + if let Some(e) = orig_string.get(s..).unwrap_or_default().find(' ') + { + orig_string + .get(s..) + .unwrap_or("Chrome") + .get(..e) + .unwrap_or("Chrome") + .replace('/', " ") + } else { + "Chrome".to_string() + } + } else if orig_string.contains("Linux") { + "GNOME Web".to_string() + } else { + string.get(s..).unwrap_or("Safari").replace('/', " ") + } + } else if string.contains("Edg ") { + string.replace("Edg ", "Edge ") + } else if string.contains("OPR ") { + string.replace("OPR ", "Opera ") + } else { + string + }) +} + +#[inline(always)] +pub(crate) fn hostname() -> Result { + document_domain() + .filter(|x| !x.is_empty()) + .ok_or_else(|| Error::new(ErrorKind::NotFound, "Domain missing")) +} + +pub(crate) fn distro() -> Result { + let string = + user_agent().ok_or_else(|| Error::from(ErrorKind::PermissionDenied))?; + let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); + let begin = string.find('(').ok_or_else(err)?; + let end = string.find(')').ok_or_else(err)?; + let string = &string[begin + 1..end]; + + Ok(if string.contains("Win32") || string.contains("Win64") { + let begin = if let Some(b) = string.find("NT") { + b + } else { + return Ok("Windows".to_string()); + }; + let end = if let Some(e) = string.find('.') { + e + } else { + return Ok("Windows".to_string()); + }; + let string = &string[begin + 3..end]; + + format!("Windows {}", string) + } else if string.contains("Linux") { + let string = if string.contains("X11") || string.contains("Wayland") { + let begin = if let Some(b) = string.find(';') { + b + } else { + return Ok("Unknown Linux".to_string()); + }; + &string[begin + 2..] + } else { + string + }; + + if string.starts_with("Linux") { + "Unknown Linux".to_string() + } else { + let end = if let Some(e) = string.find(';') { + e + } else { + return Ok("Unknown Linux".to_string()); + }; + string[..end].to_string() + } + } else if let Some(begin) = string.find("Mac OS X") { + if let Some(end) = string[begin..].find(';') { + string[begin..begin + end].to_string() + } else { + string[begin..].to_string().replace('_', ".") + } + } else { + // TODO: + // Platform::FreeBsd, + // Platform::Ios, + // Platform::Android, + // Platform::Nintendo, + // Platform::Xbox, + // Platform::PlayStation, + // Platform::Dive, + // Platform::Fuchsia, + // Platform::Redox + string.to_string() + }) +} + +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::WebBrowser +} + +pub(crate) fn platform() -> Platform { + let string = user_agent().unwrap_or_default(); + + let begin = if let Some(b) = string.find('(') { + b + } else { + return Platform::Unknown("Unknown".to_string()); + }; + let end = if let Some(e) = string.find(')') { + e + } else { + return Platform::Unknown("Unknown".to_string()); + }; + let string = &string[begin + 1..end]; + + if string.contains("Win32") || string.contains("Win64") { + Platform::Windows + } else if string.contains("Linux") { + Platform::Linux + } else if string.contains("Mac OS X") { + Platform::MacOS + } else { + // TODO: + // Platform::FreeBsd, + // Platform::Ios, + // Platform::Android, + // Platform::Nintendo, + // Platform::Xbox, + // Platform::PlayStation, + // Platform::Dive, + // Platform::Fuchsia, + // Platform::Redox, + Platform::Unknown(string.to_string()) + } +} + +pub(crate) fn arch() -> Arch { + if cfg!(target_pointer_width = "64") { + Arch::Wasm64 + } else { + Arch::Wasm32 + } +} diff --git a/src/windows.rs b/src/windows.rs index a0efb6a..cb14273 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,484 +1,484 @@ -use std::{ - convert::TryInto, - ffi::OsString, - io::Error, - mem::MaybeUninit, - os::{ - raw::{c_char, c_int, c_uchar, c_ulong, c_ushort, c_void}, - windows::ffi::OsStringExt, - }, - ptr, -}; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[repr(C)] -struct OsVersionInfoEx { - os_version_info_size: c_ulong, - major_version: c_ulong, - minor_version: c_ulong, - build_number: c_ulong, - platform_id: c_ulong, - sz_csd_version: [u16; 128], - service_pack_major: c_ushort, - service_pack_minor: c_ushort, - suite_mask: c_ushort, - product_type: c_uchar, - reserved: c_uchar, -} - -// Source: -// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#syntax -#[repr(C)] -struct SystemInfo { - processor_architecture: c_ushort, - reserved: c_ushort, - dw_page_size: c_ulong, - minimum_application_address: *mut c_void, - maximum_application_address: *mut c_void, - active_processor_mask: usize, - number_of_processors: c_ulong, - processor_type: c_ulong, - allocation_granularity: c_ulong, - processor_level: c_ushort, - processor_revision: c_ushort, -} - -#[allow(unused)] -#[repr(C)] -enum ExtendedNameFormat { - Unknown, // Nothing - FullyQualifiedDN, // Nothing - SamCompatible, // Hostname Followed By Username - Display, // Full Name - UniqueId, // Nothing - Canonical, // Nothing - UserPrincipal, // Nothing - CanonicalEx, // Nothing - ServicePrincipal, // Nothing - DnsDomain, // Nothing - GivenName, // Nothing - Surname, // Nothing -} - -#[allow(unused)] -#[repr(C)] -enum ComputerNameFormat { - NetBIOS, // Same as GetComputerNameW - DnsHostname, // Fancy Name - DnsDomain, // Nothing - DnsFullyQualified, // Fancy Name with, for example, .com - PhysicalNetBIOS, // Same as GetComputerNameW - PhysicalDnsHostname, // Same as GetComputerNameW - PhysicalDnsDomain, // Nothing - PhysicalDnsFullyQualified, // Fancy Name with, for example, .com - Max, -} - -const ERR_MORE_DATA: i32 = 0xEA; -const ERR_INSUFFICIENT_BUFFER: i32 = 0x7A; - -#[link(name = "secur32")] -extern "system" { - fn GetUserNameExW( - a: ExtendedNameFormat, - b: *mut c_char, - c: *mut c_ulong, - ) -> c_uchar; - fn GetUserNameW(a: *mut c_char, b: *mut c_ulong) -> c_int; - fn GetComputerNameExW( - a: ComputerNameFormat, - b: *mut c_char, - c: *mut c_ulong, - ) -> c_int; -} - -#[link(name = "kernel32")] -extern "system" { - fn GetUserPreferredUILanguages( - dw_flags: c_ulong, - pul_num_languages: *mut c_ulong, - pwsz_languages_buffer: *mut u16, - pcch_languages_buffer: *mut c_ulong, - ) -> c_int; - fn GetNativeSystemInfo(system_info: *mut SystemInfo); -} - -// Convert an OsString into a String -fn string_from_os(string: OsString) -> String { - match string.into_string() { - Ok(string) => string, - Err(string) => string.to_string_lossy().to_string(), - } -} - -pub(crate) fn username() -> Result { - Ok(string_from_os(username_os()?)) -} - -pub(crate) fn username_os() -> Result { - // Step 1. Retreive the entire length of the username - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetUserNameW(ptr::null_mut(), &mut size) == 0 - }; - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - size = name.capacity().try_into().unwrap_or(std::u32::MAX); - let orig_size = size; - let fail = - unsafe { GetUserNameW(name.as_mut_ptr().cast(), &mut size) == 0 }; - if fail { - return Err(Error::last_os_error()); - } - debug_assert_eq!(orig_size, size); - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - let terminator = name.pop(); // Remove Trailing Null - debug_assert_eq!(terminator, Some(0u16)); - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok(string_from_os(realname_os()?)) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - // Step 1. Retrieve the entire length of the username - let mut buf_size = 0; - let fail = unsafe { - GetUserNameExW( - ExtendedNameFormat::Display, - ptr::null_mut(), - &mut buf_size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_MORE_DATA) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(buf_size.try_into().unwrap_or(std::usize::MAX)); - let mut name_len = name.capacity().try_into().unwrap_or(std::u32::MAX); - let fail = unsafe { - GetUserNameExW( - ExtendedNameFormat::Display, - name.as_mut_ptr().cast(), - &mut name_len, - ) == 0 - }; - if fail { - return Err(Error::last_os_error()); - } - - assert_eq!(buf_size, name_len + 1); - - unsafe { - name.set_len(name_len.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -#[inline(always)] -pub(crate) fn devicename() -> Result { - Ok(string_from_os(devicename_os()?)) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - // Step 1. Retreive the entire length of the device name - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetComputerNameExW( - ComputerNameFormat::DnsHostname, - ptr::null_mut(), - &mut size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); - - if unsafe { - GetComputerNameExW( - ComputerNameFormat::DnsHostname, - name.as_mut_ptr().cast(), - &mut size, - ) == 0 - } { - return Err(Error::last_os_error()); - } - - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -pub(crate) fn hostname() -> Result { - Ok(string_from_os(hostname_os()?)) -} - -fn hostname_os() -> Result { - // Step 1. Retreive the entire length of the username - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetComputerNameExW( - ComputerNameFormat::NetBIOS, - ptr::null_mut(), - &mut size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); - - if unsafe { - GetComputerNameExW( - ComputerNameFormat::NetBIOS, - name.as_mut_ptr().cast(), - &mut size, - ) == 0 - } { - return Err(Error::last_os_error()); - } - - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -pub(crate) fn distro() -> Result { - // Due to MingW Limitations, we must dynamically load ntdll.dll - extern "system" { - fn LoadLibraryExW( - filename: *const u16, - hfile: *mut c_void, - dwflags: c_ulong, - ) -> *mut c_void; - fn FreeLibrary(hmodule: *mut c_void) -> i32; - fn GetProcAddress( - hmodule: *mut c_void, - procname: *const c_char, - ) -> *mut c_void; - } - - let mut path = "ntdll.dll\0".encode_utf16().collect::>(); - let path = path.as_mut_ptr(); - - let inst = unsafe { LoadLibraryExW(path, ptr::null_mut(), 0x0000_0800) }; - - if inst.is_null() { - return Err(Error::last_os_error()); - } - - let mut path = "RtlGetVersion\0".bytes().collect::>(); - let path = path.as_mut_ptr().cast(); - let func = unsafe { GetProcAddress(inst, path) }; - - if func.is_null() { - if unsafe { FreeLibrary(inst) } == 0 { - return Err(Error::last_os_error()); - } - - return Err(Error::last_os_error()); - } - - let get_version: unsafe extern "system" fn(a: *mut OsVersionInfoEx) -> u32 = - unsafe { std::mem::transmute(func) }; - - let mut version = MaybeUninit::::zeroed(); - - let version = unsafe { - (*version.as_mut_ptr()).os_version_info_size = - std::mem::size_of::() as u32; - get_version(version.as_mut_ptr()); - - if FreeLibrary(inst) == 0 { - return Err(Error::last_os_error()); - } - - version.assume_init() - }; - - let product = match version.product_type { - 1 => "Workstation", - 2 => "Domain Controller", - 3 => "Server", - _ => "Unknown", - }; - - Ok(format!( - "Windows {}.{}.{} ({})", - version.major_version, - version.minor_version, - version.build_number, - product, - )) -} - -#[inline(always)] -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::Windows -} - -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Windows -} - -struct LangIter { - array: Vec, - index: usize, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if let Some(value) = self.array.get(self.index) { - self.index += 1; - - Some(value.to_string()) - } else { - None - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - let mut num_languages = 0; - let mut buffer_size = 0; - let mut buffer; - - unsafe { - assert_ne!( - GetUserPreferredUILanguages( - 0x08, /* MUI_LANGUAGE_NAME */ - &mut num_languages, - ptr::null_mut(), // List of languages. - &mut buffer_size, - ), - 0 - ); - - buffer = Vec::with_capacity(buffer_size as usize); - - assert_ne!( - GetUserPreferredUILanguages( - 0x08, /* MUI_LANGUAGE_NAME */ - &mut num_languages, - buffer.as_mut_ptr(), // List of languages. - &mut buffer_size, - ), - 0 - ); - - buffer.set_len(buffer_size as usize); - } - - // We know it ends in two null characters. - buffer.pop(); - buffer.pop(); - - // - let array = String::from_utf16_lossy(&buffer) - .split('\0') - .map(|x| x.to_string()) - .collect(); - let index = 0; - - LangIter { array, index } -} - -pub(crate) fn arch() -> Arch { - fn proc(processor_type: c_ulong) -> Result { - Ok(match processor_type { - // PROCESSOR_INTEL_386 - 386 => Arch::I386, - // PROCESSOR_INTEL_486 - 486 => Arch::Unknown("I486".to_string()), - // PROCESSOR_INTEL_PENTIUM - 586 => Arch::I586, - // PROCESSOR_INTEL_IA64 - 2200 => Arch::Unknown("IA64".to_string()), - // PROCESSOR_AMD_X8664 - 8664 => Arch::X64, - v => return Err(v), - }) - } - - let buf: SystemInfo = unsafe { - let mut buf = MaybeUninit::uninit(); - GetNativeSystemInfo(buf.as_mut_ptr()); - buf.assume_init() - }; - - // Supported architectures, source: - // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#members - match buf.processor_architecture { - // PROCESSOR_ARCHITECTURE_INTEL - 0 => Arch::I686, - // PROCESSOR_ARCHITECTURE_ARM - 5 => Arch::ArmV6, - // PROCESSOR_ARCHITECTURE_IA64 - 6 => Arch::Unknown("IA64".to_string()), - // PROCESSOR_ARCHITECTURE_AMD64 - 9 => Arch::X64, - // PROCESSOR_ARCHITECTURE_ARM64 - 12 => Arch::Arm64, - // PROCESSOR_ARCHITECTURE_UNKNOWN - 0xFFFF => proc(buf.processor_type) - .unwrap_or_else(|e| Arch::Unknown(format!("Unknown ({})", e))), - invalid => proc(buf.processor_type).unwrap_or_else(|e| { - Arch::Unknown(format!("Invalid arch: {} ({})", invalid, e)) - }), - } -} +use std::{ + convert::TryInto, + ffi::OsString, + io::Error, + mem::MaybeUninit, + os::{ + raw::{c_char, c_int, c_uchar, c_ulong, c_ushort, c_void}, + windows::ffi::OsStringExt, + }, + ptr, +}; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[repr(C)] +struct OsVersionInfoEx { + os_version_info_size: c_ulong, + major_version: c_ulong, + minor_version: c_ulong, + build_number: c_ulong, + platform_id: c_ulong, + sz_csd_version: [u16; 128], + service_pack_major: c_ushort, + service_pack_minor: c_ushort, + suite_mask: c_ushort, + product_type: c_uchar, + reserved: c_uchar, +} + +// Source: +// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#syntax +#[repr(C)] +struct SystemInfo { + processor_architecture: c_ushort, + reserved: c_ushort, + dw_page_size: c_ulong, + minimum_application_address: *mut c_void, + maximum_application_address: *mut c_void, + active_processor_mask: usize, + number_of_processors: c_ulong, + processor_type: c_ulong, + allocation_granularity: c_ulong, + processor_level: c_ushort, + processor_revision: c_ushort, +} + +#[allow(unused)] +#[repr(C)] +enum ExtendedNameFormat { + Unknown, // Nothing + FullyQualifiedDN, // Nothing + SamCompatible, // Hostname Followed By Username + Display, // Full Name + UniqueId, // Nothing + Canonical, // Nothing + UserPrincipal, // Nothing + CanonicalEx, // Nothing + ServicePrincipal, // Nothing + DnsDomain, // Nothing + GivenName, // Nothing + Surname, // Nothing +} + +#[allow(unused)] +#[repr(C)] +enum ComputerNameFormat { + NetBIOS, // Same as GetComputerNameW + DnsHostname, // Fancy Name + DnsDomain, // Nothing + DnsFullyQualified, // Fancy Name with, for example, .com + PhysicalNetBIOS, // Same as GetComputerNameW + PhysicalDnsHostname, // Same as GetComputerNameW + PhysicalDnsDomain, // Nothing + PhysicalDnsFullyQualified, // Fancy Name with, for example, .com + Max, +} + +const ERR_MORE_DATA: i32 = 0xEA; +const ERR_INSUFFICIENT_BUFFER: i32 = 0x7A; + +#[link(name = "secur32")] +extern "system" { + fn GetUserNameExW( + a: ExtendedNameFormat, + b: *mut c_char, + c: *mut c_ulong, + ) -> c_uchar; + fn GetUserNameW(a: *mut c_char, b: *mut c_ulong) -> c_int; + fn GetComputerNameExW( + a: ComputerNameFormat, + b: *mut c_char, + c: *mut c_ulong, + ) -> c_int; +} + +#[link(name = "kernel32")] +extern "system" { + fn GetUserPreferredUILanguages( + dw_flags: c_ulong, + pul_num_languages: *mut c_ulong, + pwsz_languages_buffer: *mut u16, + pcch_languages_buffer: *mut c_ulong, + ) -> c_int; + fn GetNativeSystemInfo(system_info: *mut SystemInfo); +} + +// Convert an OsString into a String +fn string_from_os(string: OsString) -> String { + match string.into_string() { + Ok(string) => string, + Err(string) => string.to_string_lossy().to_string(), + } +} + +pub(crate) fn username() -> Result { + Ok(string_from_os(username_os()?)) +} + +pub(crate) fn username_os() -> Result { + // Step 1. Retreive the entire length of the username + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetUserNameW(ptr::null_mut(), &mut size) == 0 + }; + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + size = name.capacity().try_into().unwrap_or(std::u32::MAX); + let orig_size = size; + let fail = + unsafe { GetUserNameW(name.as_mut_ptr().cast(), &mut size) == 0 }; + if fail { + return Err(Error::last_os_error()); + } + debug_assert_eq!(orig_size, size); + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + let terminator = name.pop(); // Remove Trailing Null + debug_assert_eq!(terminator, Some(0u16)); + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok(string_from_os(realname_os()?)) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + // Step 1. Retrieve the entire length of the username + let mut buf_size = 0; + let fail = unsafe { + GetUserNameExW( + ExtendedNameFormat::Display, + ptr::null_mut(), + &mut buf_size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_MORE_DATA) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(buf_size.try_into().unwrap_or(std::usize::MAX)); + let mut name_len = name.capacity().try_into().unwrap_or(std::u32::MAX); + let fail = unsafe { + GetUserNameExW( + ExtendedNameFormat::Display, + name.as_mut_ptr().cast(), + &mut name_len, + ) == 0 + }; + if fail { + return Err(Error::last_os_error()); + } + + assert_eq!(buf_size, name_len + 1); + + unsafe { + name.set_len(name_len.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +#[inline(always)] +pub(crate) fn devicename() -> Result { + Ok(string_from_os(devicename_os()?)) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + // Step 1. Retreive the entire length of the device name + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetComputerNameExW( + ComputerNameFormat::DnsHostname, + ptr::null_mut(), + &mut size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); + + if unsafe { + GetComputerNameExW( + ComputerNameFormat::DnsHostname, + name.as_mut_ptr().cast(), + &mut size, + ) == 0 + } { + return Err(Error::last_os_error()); + } + + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +pub(crate) fn hostname() -> Result { + Ok(string_from_os(hostname_os()?)) +} + +fn hostname_os() -> Result { + // Step 1. Retreive the entire length of the username + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetComputerNameExW( + ComputerNameFormat::NetBIOS, + ptr::null_mut(), + &mut size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); + + if unsafe { + GetComputerNameExW( + ComputerNameFormat::NetBIOS, + name.as_mut_ptr().cast(), + &mut size, + ) == 0 + } { + return Err(Error::last_os_error()); + } + + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +pub(crate) fn distro() -> Result { + // Due to MingW Limitations, we must dynamically load ntdll.dll + extern "system" { + fn LoadLibraryExW( + filename: *const u16, + hfile: *mut c_void, + dwflags: c_ulong, + ) -> *mut c_void; + fn FreeLibrary(hmodule: *mut c_void) -> i32; + fn GetProcAddress( + hmodule: *mut c_void, + procname: *const c_char, + ) -> *mut c_void; + } + + let mut path = "ntdll.dll\0".encode_utf16().collect::>(); + let path = path.as_mut_ptr(); + + let inst = unsafe { LoadLibraryExW(path, ptr::null_mut(), 0x0000_0800) }; + + if inst.is_null() { + return Err(Error::last_os_error()); + } + + let mut path = "RtlGetVersion\0".bytes().collect::>(); + let path = path.as_mut_ptr().cast(); + let func = unsafe { GetProcAddress(inst, path) }; + + if func.is_null() { + if unsafe { FreeLibrary(inst) } == 0 { + return Err(Error::last_os_error()); + } + + return Err(Error::last_os_error()); + } + + let get_version: unsafe extern "system" fn(a: *mut OsVersionInfoEx) -> u32 = + unsafe { std::mem::transmute(func) }; + + let mut version = MaybeUninit::::zeroed(); + + let version = unsafe { + (*version.as_mut_ptr()).os_version_info_size = + std::mem::size_of::() as u32; + get_version(version.as_mut_ptr()); + + if FreeLibrary(inst) == 0 { + return Err(Error::last_os_error()); + } + + version.assume_init() + }; + + let product = match version.product_type { + 1 => "Workstation", + 2 => "Domain Controller", + 3 => "Server", + _ => "Unknown", + }; + + Ok(format!( + "Windows {}.{}.{} ({})", + version.major_version, + version.minor_version, + version.build_number, + product, + )) +} + +#[inline(always)] +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::Windows +} + +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Windows +} + +struct LangIter { + array: Vec, + index: usize, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if let Some(value) = self.array.get(self.index) { + self.index += 1; + + Some(value.to_string()) + } else { + None + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + let mut num_languages = 0; + let mut buffer_size = 0; + let mut buffer; + + unsafe { + assert_ne!( + GetUserPreferredUILanguages( + 0x08, /* MUI_LANGUAGE_NAME */ + &mut num_languages, + ptr::null_mut(), // List of languages. + &mut buffer_size, + ), + 0 + ); + + buffer = Vec::with_capacity(buffer_size as usize); + + assert_ne!( + GetUserPreferredUILanguages( + 0x08, /* MUI_LANGUAGE_NAME */ + &mut num_languages, + buffer.as_mut_ptr(), // List of languages. + &mut buffer_size, + ), + 0 + ); + + buffer.set_len(buffer_size as usize); + } + + // We know it ends in two null characters. + buffer.pop(); + buffer.pop(); + + // + let array = String::from_utf16_lossy(&buffer) + .split('\0') + .map(|x| x.to_string()) + .collect(); + let index = 0; + + LangIter { array, index } +} + +pub(crate) fn arch() -> Arch { + fn proc(processor_type: c_ulong) -> Result { + Ok(match processor_type { + // PROCESSOR_INTEL_386 + 386 => Arch::I386, + // PROCESSOR_INTEL_486 + 486 => Arch::Unknown("I486".to_string()), + // PROCESSOR_INTEL_PENTIUM + 586 => Arch::I586, + // PROCESSOR_INTEL_IA64 + 2200 => Arch::Unknown("IA64".to_string()), + // PROCESSOR_AMD_X8664 + 8664 => Arch::X64, + v => return Err(v), + }) + } + + let buf: SystemInfo = unsafe { + let mut buf = MaybeUninit::uninit(); + GetNativeSystemInfo(buf.as_mut_ptr()); + buf.assume_init() + }; + + // Supported architectures, source: + // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#members + match buf.processor_architecture { + // PROCESSOR_ARCHITECTURE_INTEL + 0 => Arch::I686, + // PROCESSOR_ARCHITECTURE_ARM + 5 => Arch::ArmV6, + // PROCESSOR_ARCHITECTURE_IA64 + 6 => Arch::Unknown("IA64".to_string()), + // PROCESSOR_ARCHITECTURE_AMD64 + 9 => Arch::X64, + // PROCESSOR_ARCHITECTURE_ARM64 + 12 => Arch::Arm64, + // PROCESSOR_ARCHITECTURE_UNKNOWN + 0xFFFF => proc(buf.processor_type) + .unwrap_or_else(|e| Arch::Unknown(format!("Unknown ({})", e))), + invalid => proc(buf.processor_type).unwrap_or_else(|e| { + Arch::Unknown(format!("Invalid arch: {} ({})", invalid, e)) + }), + } +} From 2bccb2c0be19c66a272cd65e974e376906438da6 Mon Sep 17 00:00:00 2001 From: sebihutanu1 Date: Mon, 22 Jan 2024 19:01:03 +0200 Subject: [PATCH 3/7] update Display trait for Platform enum --- .github/ISSUE_TEMPLATE/bug_report.md | 76 +- .github/ISSUE_TEMPLATE/custom.md | 20 +- .github/ISSUE_TEMPLATE/feature_request.md | 40 +- .github/PULL_REQUEST_TEMPLATE.md | 6 +- .github/dependabot.yml | 16 +- .github/workflows/ci.yml | 422 +++---- .gitignore | 12 +- .rustfmt.toml | 18 +- CHANGELOG.md | 544 ++++---- CODE_OF_CONDUCT.md | 152 +-- CONTRIBUTING.md | 44 +- Cargo.toml | 88 +- LICENSE_APACHE | 352 +++--- LICENSE_BOOST | 46 +- LICENSE_MIT | 38 +- README.md | 186 +-- WASM.md | 96 +- examples/os-strings.rs | 84 +- examples/web/Cargo.toml | 72 +- examples/web/README.md | 30 +- examples/web/index.html | 28 +- examples/web/rust-toolchain | 4 +- examples/web/src/lib.rs | 114 +- examples/whoami-demo.rs | 84 +- res/icon.svg | 216 ++-- rust-toolchain | 4 +- src/disp.rs | 498 ++++---- src/fake.rs | 150 +-- src/fallible.rs | 194 +-- src/lib.rs | 1202 +++++++++--------- src/unix.rs | 1362 ++++++++++----------- src/web.rs | 494 ++++---- src/windows.rs | 968 +++++++-------- 33 files changed, 3830 insertions(+), 3830 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 6867cf8..dd84ea7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,38 +1,38 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md index 3e9dad0..48d5f81 100644 --- a/.github/ISSUE_TEMPLATE/custom.md +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -1,10 +1,10 @@ ---- -name: Custom issue template -about: Describe this issue template's purpose here. -title: '' -labels: '' -assignees: '' - ---- - - +--- +name: Custom issue template +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 72718d5..bbcbbe7 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,20 +1,20 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8a09558..532d019 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,3 @@ - - - + + + diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 479c265..13b2d4f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,8 @@ -version: 2 -updates: -- package-ecosystem: cargo - directory: "/" - schedule: - interval: daily - time: "10:00" - open-pull-requests-limit: 10 +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + time: "10:00" + open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a461253..1f5f91a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,211 +1,211 @@ -on: [push, pull_request] - -name: tests - -jobs: - checks: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - tc: [nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - components: rustfmt, clippy - override: true - - run: cargo fmt --check - - run: cargo clippy -- -D warnings - checks-cross-compile: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [nightly] - cc: - - aarch64-linux-android - - i686-pc-windows-gnu - - i686-unknown-freebsd - - i686-unknown-linux-gnu - - wasm32-wasi - - x86_64-apple-darwin - - x86_64-unknown-redox - - x86_64-unknown-illumos - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - checks-cross-compile-ios: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [nightly] - cc: [aarch64-apple-ios] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - checks-cross-compile-wasm: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [nightly] - cc: [wasm32-unknown-unknown] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - components: clippy - override: true - - run: cargo update -p bumpalo --precise 3.4.0 - - run: cargo update -p web-sys --precise 0.3.55 - - run: cargo update -p js-sys --precise 0.3.55 - - run: cargo update -p wasm-bindgen --precise 0.2.78 - - run: cargo update -p log --precise 0.4.17 - - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings - - run: cargo clippy --no-default-features --target=${{ matrix.cc }} -- -D warnings - - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo clippy --target=${{ matrix.cc }} -- -D warnings - test: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest, windows-latest] - tc: [1.40.0, stable, beta, nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - override: true - - run: cargo test --all --all-features - test-macos: - runs-on: macos-latest - strategy: - matrix: - tc: [stable, beta, nightly] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - override: true - - run: cargo test --all --all-features --target=x86_64-apple-darwin - cross-compile: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.40.0, stable, beta, nightly] - cc: - - aarch64-linux-android - - i686-pc-windows-gnu - - i686-unknown-freebsd - - i686-unknown-linux-gnu - - wasm32-wasi - - x86_64-apple-darwin - - x86_64-unknown-redox - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-ios: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [1.40.0, stable, beta, nightly] - cc: [aarch64-apple-ios] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-m1: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-latest] - tc: [stable, beta, nightly] - cc: [aarch64-apple-darwin] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} - cross-compile-wasm: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.40.0, stable, beta, nightly] - cc: [wasm32-unknown-unknown] - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo update -p bumpalo --precise 3.4.0 - - run: cargo update -p web-sys --precise 0.3.55 - - run: cargo update -p js-sys --precise 0.3.55 - - run: cargo update -p wasm-bindgen --precise 0.2.78 - - run: cargo update -p log --precise 0.4.17 - - run: cargo update -p quote --precise 1.0.30 - - run: cargo update -p proc-macro2 --precise 1.0.63 - - run: cargo build --all-features --target=${{ matrix.cc }} - - run: cargo build --no-default-features --target=${{ matrix.cc }} - - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo build --target=${{ matrix.cc }} - cross-compile-illumos: - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [ubuntu-latest] - tc: [1.65.0, stable, beta, nightly] - cc: - - x86_64-unknown-illumos - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.tc }} - target: ${{ matrix.cc }} - override: true - - run: cargo build --all-features --target=${{ matrix.cc }} +on: [push, pull_request] + +name: tests + +jobs: + checks: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + tc: [nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + components: rustfmt, clippy + override: true + - run: cargo fmt --check + - run: cargo clippy -- -D warnings + checks-cross-compile: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [nightly] + cc: + - aarch64-linux-android + - i686-pc-windows-gnu + - i686-unknown-freebsd + - i686-unknown-linux-gnu + - wasm32-wasi + - x86_64-apple-darwin + - x86_64-unknown-redox + - x86_64-unknown-illumos + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + checks-cross-compile-ios: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [nightly] + cc: [aarch64-apple-ios] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + checks-cross-compile-wasm: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [nightly] + cc: [wasm32-unknown-unknown] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + components: clippy + override: true + - run: cargo update -p bumpalo --precise 3.4.0 + - run: cargo update -p web-sys --precise 0.3.55 + - run: cargo update -p js-sys --precise 0.3.55 + - run: cargo update -p wasm-bindgen --precise 0.2.78 + - run: cargo update -p log --precise 0.4.17 + - run: cargo clippy --all-features --target=${{ matrix.cc }} -- -D warnings + - run: cargo clippy --no-default-features --target=${{ matrix.cc }} -- -D warnings + - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo clippy --target=${{ matrix.cc }} -- -D warnings + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest] + tc: [1.40.0, stable, beta, nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + override: true + - run: cargo test --all --all-features + test-macos: + runs-on: macos-latest + strategy: + matrix: + tc: [stable, beta, nightly] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + override: true + - run: cargo test --all --all-features --target=x86_64-apple-darwin + cross-compile: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.40.0, stable, beta, nightly] + cc: + - aarch64-linux-android + - i686-pc-windows-gnu + - i686-unknown-freebsd + - i686-unknown-linux-gnu + - wasm32-wasi + - x86_64-apple-darwin + - x86_64-unknown-redox + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-ios: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [1.40.0, stable, beta, nightly] + cc: [aarch64-apple-ios] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-m1: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + tc: [stable, beta, nightly] + cc: [aarch64-apple-darwin] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} + cross-compile-wasm: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.40.0, stable, beta, nightly] + cc: [wasm32-unknown-unknown] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo update -p bumpalo --precise 3.4.0 + - run: cargo update -p web-sys --precise 0.3.55 + - run: cargo update -p js-sys --precise 0.3.55 + - run: cargo update -p wasm-bindgen --precise 0.2.78 + - run: cargo update -p log --precise 0.4.17 + - run: cargo update -p quote --precise 1.0.30 + - run: cargo update -p proc-macro2 --precise 1.0.63 + - run: cargo build --all-features --target=${{ matrix.cc }} + - run: cargo build --no-default-features --target=${{ matrix.cc }} + - run: RUSTFLAGS="--cfg target_os=\"daku\"" cargo build --target=${{ matrix.cc }} + cross-compile-illumos: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + tc: [1.65.0, stable, beta, nightly] + cc: + - x86_64-unknown-illumos + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.tc }} + target: ${{ matrix.cc }} + override: true + - run: cargo build --all-features --target=${{ matrix.cc }} diff --git a/.gitignore b/.gitignore index 39ca62a..7ed80a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -**/target/ -**/*.rs.bk -Cargo.lock -/ignore/ -/a.out -/**/*.swp +**/target/ +**/*.rs.bk +Cargo.lock +/ignore/ +/a.out +/**/*.swp diff --git a/.rustfmt.toml b/.rustfmt.toml index 48239b7..5e6866e 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -1,9 +1,9 @@ -# Don't deviate too much, just reduce columns and stricter enforcement -edition = "2021" -unstable_features = true -max_width = 80 -reorder_impl_items = true -group_imports = "StdExternalCrate" -imports_granularity = "Crate" -normalize_doc_attributes = true -wrap_comments = true +# Don't deviate too much, just reduce columns and stricter enforcement +edition = "2021" +unstable_features = true +max_width = 80 +reorder_impl_items = true +group_imports = "StdExternalCrate" +imports_granularity = "Crate" +normalize_doc_attributes = true +wrap_comments = true diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a92849..04841f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,272 +1,272 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog], and this project adheres to -[Semantic Versioning]. - -## [1.4.1] - 2023-06-25 -### Fixed - - License files not being included in package on crates.io - -## [1.4.0] - 2023-03-12 -### Added - - Support for Illumos - -## [1.3.0] - 2022-12-28 -### Added - - `Arch` enum listing CPU architectures - - `Width` enum listing CPU architecture address widths - - `arch()` function which returns an `Arch` type representing a CPU - architecture - - `Arch::width()` method which returns the address width of a CPU architecture - - *`web`* feature (enabled by default). Disabling this feature allows you to - use wasm32-unknown-unknown with whoami outside of the browser with a mock - implementation. - - Officially support compiling to WASI or Daku WebAssembly platforms; - functionality not supported yet. - - Convenience `Result` type alias. - -### Changed - - Modernized and cleaned up code style - -### Fixed - - Handling of `lang()` when `$LANG` environment variable on unix set to "C", - causing duplicated iterator elements `["C", "C"]`; now produces `["en-US"]`. - - WhoAmI reporting "Safari" when running in Chrome/Chromium browser - - WhoAmI reporting "Edg" when running in Edge browser (now reports "Edge") - - WhoAmI reporting "OPR" when running in Opera browser (now reports "Opera") - - WhoAmI reporting "Mozilla" when running in GNOME web browser (now reports - "GNOME Web") - -## [1.2.3] - 2022-09-12 -### Fixed - - WebAssembly target requiring older versions of dependencies - -## [1.2.2] - 2022-09-05 -### Added - - More details to the method documentation - -### Changed - - WhoAmI now has an official MSRV of Rust 1.40.0 - - `whoami::hostname()` is now normalized to lowercase - -## [1.2.1] - 2021-11-24 -### Fixed - - The Windows GNU target support being broken - -## [1.2.0] - 2021-11-06 -### Added - - Derives for `Clone`, `PartialEq` and `Eq` on `DesktopEnv` and `Platform` - -### Changed - - Lower MSRV for Windows - -## [1.1.5] - 2021-09-28 -### Fixed - - Segfault that occurs when passwd entry missing in docker - -## [1.1.4] - 2021-09-26 -### Changed - - There are no longer any known panics within the code, all possible panics - with whoami are now considered bugs. - - If any of the primary functions return an empty string, whoami should now - return "Unknown" or"unknown", or for `hostname()`, "localhost". - -### Fixed - - Panicking in situations where certain files don't exist / OS functions fail. - -## [1.1.3] - 2021-08-17 -### Fixed - - Circumstance where whoami points to invalid memory on Linux. - -## [1.1.2] - 2021-04-03 -### Fixed - - Not parsing the gecos field properly on unix systems (affects the - `realname()` and `realname_os()` functions; they will no longer return - extraneous commas on some systems). - -## [1.1.1] - 2021-03-13 -### Fixed - - Not compiling on target `x86_64-pc-windows-gnu`. - -## [1.1.0] - 2021-01-17 -### Added - - `lang()` function which returns an iterator over user's preferred language(s) - -## [1.0.3] - 2020-12-31 -### Fixed - - Link to logo in documentation. - -## [1.0.2] - 2020-12-31 -### Changed - - `distro()` on Windows now returns more detailed version. - -## [1.0.1] - 2020-12-16 -### Added - - Official support for BSD and variants - -### Fixed - - `platform()` will now return `Platform::Bsd` when running BSD. - - Misaligned address error on FreeBSD when calling `username()`. - -## [1.0.0] - 2020-11-23 -### Removed - - `Platform::Dive` and `DesktopEnv::Dive`, as that was an OS idea not a real OS - - Explicit support for `stdweb`, now built on `web-sys`/`wasm-bindgen`. - -## [0.9.0] - 2020-06-24 -### Added - - `stdweb` and `wasm-bindgen` support - - Versions of `-> String` functions that return `OsString`s: - - `devicename_os()` - - `distro_os()` - - `hostname_os()` - - `realname_os()` - - `username_os()` - -### Changed - - Renamed `DesktopEnv::Mac` to `DesktopEnv::Aqua` - - Renamed `DesktopEnv::Wasm` to `DesktopEnv::WebBrowser` - - Renamed `DesktopEnv::Redox` to `DesktopEnv::Orbital` - - Renamed `DesktopEnv::Fuchsia` to `DesktopEnv::Ermine` - - Renamed `Platform::FreeBsd` to `Platform::Bsd` - - Renamed `env()` to `desktop_env()` - - Renamed `host()` to `devicename()` - - Renamed `os()` to `distro()` - - Renamed `user()` to `realname()` - -### Fixed - - Inconsistencies on Windows - - MacOS running commands instead of using native APIs (this results in speed - improvements on MacOS) - - One of the Linux functions also using commands instead of native APIs (faster) - -### Contributors -Thanks to everyone who contributed to make this version of whoami possible! - -- [AldaronLau](https://github.com/AldaronLau) -- [Vlad-Shcherbina](https://github.com/Vlad-Shcherbina) - -## [0.8.2] - 2020-06-11 -### Changed - - Windows `host()` and `hostname()` now behave like they do on Linux and MacOS - -### Fixed - - Windows FFI Undefined Behavior because of not checking for errors - - Cross-compiling from Linux to Windows not working - -## [0.8.1] - 2020-02-22 -### Fixed - - Remove unnecessary use of `to_mut()` on `Cow`s returned from - `String::from_utf8_lossy()`. - -## [0.8.0] - 2020-02-21 -### Added - - Detection for KDE desktop environment. - -### Changed - - Unknown desktop environment may now contain lowercase characters. - -### Fixed - - No longer unwraps in any place where bad data from the OS could cause - a panic. - -## [0.7.0] - 2019-12-21 -### Removed - - `stdweb` dependency when targetting web assembly. - -### Changed - - All public enums now have the attribute `#[non_exhaustive]` and derive - `Debug`. - -### Fixed - - Some out-of-date documentation - -## [0.6.0] - 2019-10-25 -### Added - - Web Assembly support. - -### Removed - - `Platform::Web` variant of enum, use `env()` if you need to. - -### Changed - - `platform()` is no longer a const fn (needed for wasm platform - detection). - -## [0.5.3] - 2019-07-18 -### Changed - - Now uses a more modern Rust coding style (replace `::std::` with `std::`). - - Now uses a more modern Rust coding style with `mem::MaybeUninit`. - - `impl Display` for desktop environment now uses proper capitalization. - - Don't depend on `libc` anymore. -### Fixed - - Fancy Names not working on Windows - - `user()` now uses Windows Display Name on Windows rather than the username. - - `host()` now uses Windows Name DNS Fully Qualified rather than the hostname. - -## [0.5.2] - 2019-05-12 -### Fixed - - Fixed more broken links! - -## [0.5.1] - 2019-05-12 -### Fixed - - Clippy lint warning: change `expect(&format!("…"))` to `expect("…")` for optimization in 2 cases. - - Fixed broken links - -## [0.5.0] - 2019-03-17 -### Added - - `Platform` enum with corresponding `platform()` function. - - `Dive`, `Fuchsia`, and `Redox` to `DesktopEnv` enum. -### Changed - - Started using `const fn` for some functions. - -## [0.4.1] - 2019-01-12 -### Fixed - - Fixed README errors. - -## [0.4.0] - 2019-01-12 -### Added - - MacOS support. -### Changed - - `env` on Ubuntu now returns DesktopEnv::Ubuntu instead of DesktopEnv::Other("UBUNTU") - - Split off the binary into `whome` (who me?) crate - -## [0.3.0] - 2019-01-04 -### Added - - Added more fallbacks. -### Changed - - Rename realname -> user - - Rename computer -> host -### Fixed - - Fix typo for uknown -> unknown. - -## [0.2.4] - 2018-12-04 -### Fixed - - Works now on platforms that use u8 instead of i8 for chars (like ARM). - -## [0.2.3] - 2018-11-26 -### Fixed - - Trailing newline on Windows. - -## [0.2.2] - 2018-06-02 -### Fixed - - Typo in markdown. - -## [0.2.1] - 2018-06-02 -### Fixed - - Undefined behavior on Linux. - -## [0.2.0] - 2017-12-28 -### Added - - Windows support. - -## [0.1.1] - 2017-08-04 -### Fixed - - Something in the markdown. - -## [0.1.0] - 2017-08-04 -### Added - - Published to crates.io. - -[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ -[Semantic Versioning]: https://github.com/AldaronLau/semver/ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog], and this project adheres to +[Semantic Versioning]. + +## [1.4.1] - 2023-06-25 +### Fixed + - License files not being included in package on crates.io + +## [1.4.0] - 2023-03-12 +### Added + - Support for Illumos + +## [1.3.0] - 2022-12-28 +### Added + - `Arch` enum listing CPU architectures + - `Width` enum listing CPU architecture address widths + - `arch()` function which returns an `Arch` type representing a CPU + architecture + - `Arch::width()` method which returns the address width of a CPU architecture + - *`web`* feature (enabled by default). Disabling this feature allows you to + use wasm32-unknown-unknown with whoami outside of the browser with a mock + implementation. + - Officially support compiling to WASI or Daku WebAssembly platforms; + functionality not supported yet. + - Convenience `Result` type alias. + +### Changed + - Modernized and cleaned up code style + +### Fixed + - Handling of `lang()` when `$LANG` environment variable on unix set to "C", + causing duplicated iterator elements `["C", "C"]`; now produces `["en-US"]`. + - WhoAmI reporting "Safari" when running in Chrome/Chromium browser + - WhoAmI reporting "Edg" when running in Edge browser (now reports "Edge") + - WhoAmI reporting "OPR" when running in Opera browser (now reports "Opera") + - WhoAmI reporting "Mozilla" when running in GNOME web browser (now reports + "GNOME Web") + +## [1.2.3] - 2022-09-12 +### Fixed + - WebAssembly target requiring older versions of dependencies + +## [1.2.2] - 2022-09-05 +### Added + - More details to the method documentation + +### Changed + - WhoAmI now has an official MSRV of Rust 1.40.0 + - `whoami::hostname()` is now normalized to lowercase + +## [1.2.1] - 2021-11-24 +### Fixed + - The Windows GNU target support being broken + +## [1.2.0] - 2021-11-06 +### Added + - Derives for `Clone`, `PartialEq` and `Eq` on `DesktopEnv` and `Platform` + +### Changed + - Lower MSRV for Windows + +## [1.1.5] - 2021-09-28 +### Fixed + - Segfault that occurs when passwd entry missing in docker + +## [1.1.4] - 2021-09-26 +### Changed + - There are no longer any known panics within the code, all possible panics + with whoami are now considered bugs. + - If any of the primary functions return an empty string, whoami should now + return "Unknown" or"unknown", or for `hostname()`, "localhost". + +### Fixed + - Panicking in situations where certain files don't exist / OS functions fail. + +## [1.1.3] - 2021-08-17 +### Fixed + - Circumstance where whoami points to invalid memory on Linux. + +## [1.1.2] - 2021-04-03 +### Fixed + - Not parsing the gecos field properly on unix systems (affects the + `realname()` and `realname_os()` functions; they will no longer return + extraneous commas on some systems). + +## [1.1.1] - 2021-03-13 +### Fixed + - Not compiling on target `x86_64-pc-windows-gnu`. + +## [1.1.0] - 2021-01-17 +### Added + - `lang()` function which returns an iterator over user's preferred language(s) + +## [1.0.3] - 2020-12-31 +### Fixed + - Link to logo in documentation. + +## [1.0.2] - 2020-12-31 +### Changed + - `distro()` on Windows now returns more detailed version. + +## [1.0.1] - 2020-12-16 +### Added + - Official support for BSD and variants + +### Fixed + - `platform()` will now return `Platform::Bsd` when running BSD. + - Misaligned address error on FreeBSD when calling `username()`. + +## [1.0.0] - 2020-11-23 +### Removed + - `Platform::Dive` and `DesktopEnv::Dive`, as that was an OS idea not a real OS + - Explicit support for `stdweb`, now built on `web-sys`/`wasm-bindgen`. + +## [0.9.0] - 2020-06-24 +### Added + - `stdweb` and `wasm-bindgen` support + - Versions of `-> String` functions that return `OsString`s: + - `devicename_os()` + - `distro_os()` + - `hostname_os()` + - `realname_os()` + - `username_os()` + +### Changed + - Renamed `DesktopEnv::Mac` to `DesktopEnv::Aqua` + - Renamed `DesktopEnv::Wasm` to `DesktopEnv::WebBrowser` + - Renamed `DesktopEnv::Redox` to `DesktopEnv::Orbital` + - Renamed `DesktopEnv::Fuchsia` to `DesktopEnv::Ermine` + - Renamed `Platform::FreeBsd` to `Platform::Bsd` + - Renamed `env()` to `desktop_env()` + - Renamed `host()` to `devicename()` + - Renamed `os()` to `distro()` + - Renamed `user()` to `realname()` + +### Fixed + - Inconsistencies on Windows + - MacOS running commands instead of using native APIs (this results in speed + improvements on MacOS) + - One of the Linux functions also using commands instead of native APIs (faster) + +### Contributors +Thanks to everyone who contributed to make this version of whoami possible! + +- [AldaronLau](https://github.com/AldaronLau) +- [Vlad-Shcherbina](https://github.com/Vlad-Shcherbina) + +## [0.8.2] - 2020-06-11 +### Changed + - Windows `host()` and `hostname()` now behave like they do on Linux and MacOS + +### Fixed + - Windows FFI Undefined Behavior because of not checking for errors + - Cross-compiling from Linux to Windows not working + +## [0.8.1] - 2020-02-22 +### Fixed + - Remove unnecessary use of `to_mut()` on `Cow`s returned from + `String::from_utf8_lossy()`. + +## [0.8.0] - 2020-02-21 +### Added + - Detection for KDE desktop environment. + +### Changed + - Unknown desktop environment may now contain lowercase characters. + +### Fixed + - No longer unwraps in any place where bad data from the OS could cause + a panic. + +## [0.7.0] - 2019-12-21 +### Removed + - `stdweb` dependency when targetting web assembly. + +### Changed + - All public enums now have the attribute `#[non_exhaustive]` and derive + `Debug`. + +### Fixed + - Some out-of-date documentation + +## [0.6.0] - 2019-10-25 +### Added + - Web Assembly support. + +### Removed + - `Platform::Web` variant of enum, use `env()` if you need to. + +### Changed + - `platform()` is no longer a const fn (needed for wasm platform + detection). + +## [0.5.3] - 2019-07-18 +### Changed + - Now uses a more modern Rust coding style (replace `::std::` with `std::`). + - Now uses a more modern Rust coding style with `mem::MaybeUninit`. + - `impl Display` for desktop environment now uses proper capitalization. + - Don't depend on `libc` anymore. +### Fixed + - Fancy Names not working on Windows + - `user()` now uses Windows Display Name on Windows rather than the username. + - `host()` now uses Windows Name DNS Fully Qualified rather than the hostname. + +## [0.5.2] - 2019-05-12 +### Fixed + - Fixed more broken links! + +## [0.5.1] - 2019-05-12 +### Fixed + - Clippy lint warning: change `expect(&format!("…"))` to `expect("…")` for optimization in 2 cases. + - Fixed broken links + +## [0.5.0] - 2019-03-17 +### Added + - `Platform` enum with corresponding `platform()` function. + - `Dive`, `Fuchsia`, and `Redox` to `DesktopEnv` enum. +### Changed + - Started using `const fn` for some functions. + +## [0.4.1] - 2019-01-12 +### Fixed + - Fixed README errors. + +## [0.4.0] - 2019-01-12 +### Added + - MacOS support. +### Changed + - `env` on Ubuntu now returns DesktopEnv::Ubuntu instead of DesktopEnv::Other("UBUNTU") + - Split off the binary into `whome` (who me?) crate + +## [0.3.0] - 2019-01-04 +### Added + - Added more fallbacks. +### Changed + - Rename realname -> user + - Rename computer -> host +### Fixed + - Fix typo for uknown -> unknown. + +## [0.2.4] - 2018-12-04 +### Fixed + - Works now on platforms that use u8 instead of i8 for chars (like ARM). + +## [0.2.3] - 2018-11-26 +### Fixed + - Trailing newline on Windows. + +## [0.2.2] - 2018-06-02 +### Fixed + - Typo in markdown. + +## [0.2.1] - 2018-06-02 +### Fixed + - Undefined behavior on Linux. + +## [0.2.0] - 2017-12-28 +### Added + - Windows support. + +## [0.1.1] - 2017-08-04 +### Fixed + - Something in the markdown. + +## [0.1.0] - 2017-08-04 +### Added + - Published to crates.io. + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ +[Semantic Versioning]: https://github.com/AldaronLau/semver/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index efdbb5b..b19a756 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,76 +1,76 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at aldaronlau@gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at aldaronlau@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 635bae5..8fc20ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,22 +1,22 @@ -# Contributing -Anyone is welcome to contribute! You can [open an issue], -[Post to GitHub Discussions] or [send me an email] about anything related to -this project. You may also [open a PR]. I don't require PRs to be formatted in -a specific manner, since I'll run it through rustfmt after the merge anyway. If -you're going to work on a PR, it would be preferred to let me know ahead of time -(unless it's a quick fix), and open a draft PR if it's a large one. Then I'll -assign the issue to you. Otherwise, I can't guarantee I won't duplicate your -work. If I can't contact you within a week, I may unassign you and finish your -work (opening a Draft PR on this repository puts your code under this crate's -license). - -If you open a bug report, you can usually expect it to be fixed within a week. -If you open a feature request it may stay open indefinitely, until I need it -too. I mark feature requests as "enhancements" on GitHub issues. - -Happy coding! - -[open an issue]: https://github.com/ardaku/whoami/issues -[send me an email]: mailto:aldaronlau@gmail.com -[open a PR]: https://github.com/ardaku/whoami/pulls -[Post to GitHub Discussions]: https://github.com/ardaku/whoami/discussions +# Contributing +Anyone is welcome to contribute! You can [open an issue], +[Post to GitHub Discussions] or [send me an email] about anything related to +this project. You may also [open a PR]. I don't require PRs to be formatted in +a specific manner, since I'll run it through rustfmt after the merge anyway. If +you're going to work on a PR, it would be preferred to let me know ahead of time +(unless it's a quick fix), and open a draft PR if it's a large one. Then I'll +assign the issue to you. Otherwise, I can't guarantee I won't duplicate your +work. If I can't contact you within a week, I may unassign you and finish your +work (opening a Draft PR on this repository puts your code under this crate's +license). + +If you open a bug report, you can usually expect it to be fixed within a week. +If you open a feature request it may stay open indefinitely, until I need it +too. I mark feature requests as "enhancements" on GitHub issues. + +Happy coding! + +[open an issue]: https://github.com/ardaku/whoami/issues +[send me an email]: mailto:aldaronlau@gmail.com +[open a PR]: https://github.com/ardaku/whoami/pulls +[Post to GitHub Discussions]: https://github.com/ardaku/whoami/discussions diff --git a/Cargo.toml b/Cargo.toml index 44941be..8702019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,44 +1,44 @@ -[package] -name = "whoami" -version = "1.4.1" -edition = "2018" -license = "Apache-2.0 OR BSL-1.0 OR MIT" -documentation = "https://docs.rs/whoami" -homepage = "https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md" -repository = "https://github.com/ardaku/whoami" -readme = "README.md" -description = "Retrieve the current user and environment." -keywords = ["user", "username", "whoami", "platform", "detect"] -categories = [ - "os", - "wasm", - "internationalization", - "localization", - "value-formatting", -] -include = [ - "LICENSE_APACHE", - "LICENSE_BOOST", - "LICENSE_MIT", - "README.md", - "src/*", -] -rust-version = "1.40" - -# Target-specific dependency required to work with wasm-bindgen -[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.web-sys] -version = "0.3" -features = ["Navigator", "Document", "Window", "Location"] -optional = true -[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.wasm-bindgen] -version = "0.2" -optional = true - -[features] -default = ["web"] -# Enabling this feature indicates that the wasm32-unknown-unknown target should -# be assumed to be in a web environment where it can call DOM APIs. -web = ["web-sys", "wasm-bindgen"] - -[dependencies] -ansi_term = "0.12.0" \ No newline at end of file +[package] +name = "whoami" +version = "1.4.1" +edition = "2018" +license = "Apache-2.0 OR BSL-1.0 OR MIT" +documentation = "https://docs.rs/whoami" +homepage = "https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md" +repository = "https://github.com/ardaku/whoami" +readme = "README.md" +description = "Retrieve the current user and environment." +keywords = ["user", "username", "whoami", "platform", "detect"] +categories = [ + "os", + "wasm", + "internationalization", + "localization", + "value-formatting", +] +include = [ + "LICENSE_APACHE", + "LICENSE_BOOST", + "LICENSE_MIT", + "README.md", + "src/*", +] +rust-version = "1.40" + +# Target-specific dependency required to work with wasm-bindgen +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.web-sys] +version = "0.3" +features = ["Navigator", "Document", "Window", "Location"] +optional = true +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi"), not(target_os = "daku")))'.dependencies.wasm-bindgen] +version = "0.2" +optional = true + +[features] +default = ["web"] +# Enabling this feature indicates that the wasm32-unknown-unknown target should +# be assumed to be in a web environment where it can call DOM APIs. +web = ["web-sys", "wasm-bindgen"] + +[dependencies] +is-terminal = "0.4.10" \ No newline at end of file diff --git a/LICENSE_APACHE b/LICENSE_APACHE index a2ce4d9..1b5ec8b 100644 --- a/LICENSE_APACHE +++ b/LICENSE_APACHE @@ -1,176 +1,176 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE_BOOST b/LICENSE_BOOST index 1dad8e9..36b7cd9 100644 --- a/LICENSE_BOOST +++ b/LICENSE_BOOST @@ -1,23 +1,23 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/LICENSE_MIT b/LICENSE_MIT index 9dccfa4..9cf1062 100644 --- a/LICENSE_MIT +++ b/LICENSE_MIT @@ -1,19 +1,19 @@ -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index ef9e741..b8e60d6 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,93 @@ -![WhoAmI Logo](https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg) - -#### [Changelog][3] | [Source][4] | [Getting Started][5] - -[![tests](https://github.com/ardaku/whoami/actions/workflows/ci.yml/badge.svg)](https://github.com/ardaku/whoami/actions/workflows/ci.yml) -[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/ardaku/whoami)](https://github.com/ardaku/whoami/) -[![GitHub contributors](https://img.shields.io/github/contributors/ardaku/whoami)](https://github.com/ardaku/whoami/graphs/contributors) -[![Crates.io](https://img.shields.io/crates/v/whoami)](https://crates.io/crates/whoami) -[![Crates.io](https://img.shields.io/crates/d/whoami)](https://crates.io/crates/whoami) -[![Crates.io (recent)](https://img.shields.io/crates/dr/whoami)](https://crates.io/crates/whoami) -[![Crates.io](https://img.shields.io/crates/l/whoami)](https://github.com/ardaku/whoami/search?l=Text&q=license) -[![Docs.rs](https://docs.rs/whoami/badge.svg)](https://docs.rs/whoami/) - -Retrieve the current user and environment through simple functions. - -Check out the [documentation][0] for examples. - -### Features - - Get the user's full name - - Get the user's username - - Get the user's preferred language(s) - - Get the devices's hostname - - Get the devices's "pretty" or "fancy" name - - Get the devices's desktop environment - - Get the devices's OS name and version - - Get the devices's platform name - - Get the devices's CPU architecture and its width - -### Supported Platforms -WhoAmI targets all platforms that can run Rust, including: - - Linux - - Windows - - Mac OS - - BSD variants (FreeBSD, others) - - [Web Assembly](https://github.com/ardaku/whoami/blob/stable/WASM.md) - - Mock implementation - - Web Browser - DOM - - WASI (Wasite/Quantii, others) **mock implementation, full implementation planned later** - - Daku (Ardaku/Quantii, others) **mock implementation, full implementation planned later** - - Illumos variants (SmartOS, OmniOS, others) **may partially or fully work - but untested** - - Android **may partially or fully work - but untested, planned later** - - iOS **planned later** - - Redox **planned later** - - Fuchsia **planned later** - - Various game consoles **planned later** - - Others? (make a PR or open an issue) - -## MSRV -WhoAmI 1.x.y targets Rust 1.40.0 stable and later, and the 1.x.y track will -be maintained at least until the release of the Rust 2024 edition. - -The MSRV will only be updated on major version bumps, and version 2.0.0 will -target Rust 1.65.0 and later to make use of the `let else` syntax. - -## Binary -[whome](https://crates.io/crates/whome): `whoami` command RiR (Re-written in -Rust) that depends on this crate. - -## License -Copyright © 2017-2023 The WhoAmI Contributors. - -Licensed under any of - - Apache License, Version 2.0, ([LICENSE_APACHE][7] - or [https://www.apache.org/licenses/LICENSE-2.0][8]) - - Boost Software License, Version 1.0, ([LICENSE_BOOST][11] - or [https://www.boost.org/LICENSE_1_0.txt][12]) - - MIT License, ([LICENSE_MIT][9] or [https://mit-license.org/][10]) - -at your option. - -### Contribution -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -licensed as described above, without any additional terms or conditions. - -## Help -If you want help using or contributing to this library, feel free to send me an -email at [aldaronlau@gmail.com][13]. - -[0]: https://docs.rs/whoami -[1]: https://crates.io/crates/whoami -[2]: https://github.com/ardaku/whoami/actions?query=workflow%3Atests -[3]: https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md -[4]: https://github.com/ardaku/whoami/ -[5]: https://docs.rs/whoami#getting-started -[6]: https://aldaronlau.com/ -[7]: https://github.com/ardaku/whoami/blob/stable/LICENSE_APACHE -[8]: https://www.apache.org/licenses/LICENSE-2.0 -[9]: https://github.com/ardaku/whoami/blob/stable/LICENSE_MIT -[10]: https://mit-license.org/ -[11]: https://github.com/ardaku/whoami/blob/stable/LICENSE_BOOST -[12]: https://www.boost.org/LICENSE_1_0.txt -[13]: mailto:aldaronlau@gmail.com +![WhoAmI Logo](https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg) + +#### [Changelog][3] | [Source][4] | [Getting Started][5] + +[![tests](https://github.com/ardaku/whoami/actions/workflows/ci.yml/badge.svg)](https://github.com/ardaku/whoami/actions/workflows/ci.yml) +[![GitHub commit activity](https://img.shields.io/github/commit-activity/y/ardaku/whoami)](https://github.com/ardaku/whoami/) +[![GitHub contributors](https://img.shields.io/github/contributors/ardaku/whoami)](https://github.com/ardaku/whoami/graphs/contributors) +[![Crates.io](https://img.shields.io/crates/v/whoami)](https://crates.io/crates/whoami) +[![Crates.io](https://img.shields.io/crates/d/whoami)](https://crates.io/crates/whoami) +[![Crates.io (recent)](https://img.shields.io/crates/dr/whoami)](https://crates.io/crates/whoami) +[![Crates.io](https://img.shields.io/crates/l/whoami)](https://github.com/ardaku/whoami/search?l=Text&q=license) +[![Docs.rs](https://docs.rs/whoami/badge.svg)](https://docs.rs/whoami/) + +Retrieve the current user and environment through simple functions. + +Check out the [documentation][0] for examples. + +### Features + - Get the user's full name + - Get the user's username + - Get the user's preferred language(s) + - Get the devices's hostname + - Get the devices's "pretty" or "fancy" name + - Get the devices's desktop environment + - Get the devices's OS name and version + - Get the devices's platform name + - Get the devices's CPU architecture and its width + +### Supported Platforms +WhoAmI targets all platforms that can run Rust, including: + - Linux + - Windows + - Mac OS + - BSD variants (FreeBSD, others) + - [Web Assembly](https://github.com/ardaku/whoami/blob/stable/WASM.md) + - Mock implementation + - Web Browser - DOM + - WASI (Wasite/Quantii, others) **mock implementation, full implementation planned later** + - Daku (Ardaku/Quantii, others) **mock implementation, full implementation planned later** + - Illumos variants (SmartOS, OmniOS, others) **may partially or fully work - but untested** + - Android **may partially or fully work - but untested, planned later** + - iOS **planned later** + - Redox **planned later** + - Fuchsia **planned later** + - Various game consoles **planned later** + - Others? (make a PR or open an issue) + +## MSRV +WhoAmI 1.x.y targets Rust 1.40.0 stable and later, and the 1.x.y track will +be maintained at least until the release of the Rust 2024 edition. + +The MSRV will only be updated on major version bumps, and version 2.0.0 will +target Rust 1.65.0 and later to make use of the `let else` syntax. + +## Binary +[whome](https://crates.io/crates/whome): `whoami` command RiR (Re-written in +Rust) that depends on this crate. + +## License +Copyright © 2017-2023 The WhoAmI Contributors. + +Licensed under any of + - Apache License, Version 2.0, ([LICENSE_APACHE][7] + or [https://www.apache.org/licenses/LICENSE-2.0][8]) + - Boost Software License, Version 1.0, ([LICENSE_BOOST][11] + or [https://www.boost.org/LICENSE_1_0.txt][12]) + - MIT License, ([LICENSE_MIT][9] or [https://mit-license.org/][10]) + +at your option. + +### Contribution +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +licensed as described above, without any additional terms or conditions. + +## Help +If you want help using or contributing to this library, feel free to send me an +email at [aldaronlau@gmail.com][13]. + +[0]: https://docs.rs/whoami +[1]: https://crates.io/crates/whoami +[2]: https://github.com/ardaku/whoami/actions?query=workflow%3Atests +[3]: https://github.com/ardaku/whoami/blob/stable/CHANGELOG.md +[4]: https://github.com/ardaku/whoami/ +[5]: https://docs.rs/whoami#getting-started +[6]: https://aldaronlau.com/ +[7]: https://github.com/ardaku/whoami/blob/stable/LICENSE_APACHE +[8]: https://www.apache.org/licenses/LICENSE-2.0 +[9]: https://github.com/ardaku/whoami/blob/stable/LICENSE_MIT +[10]: https://mit-license.org/ +[11]: https://github.com/ardaku/whoami/blob/stable/LICENSE_BOOST +[12]: https://www.boost.org/LICENSE_1_0.txt +[13]: mailto:aldaronlau@gmail.com diff --git a/WASM.md b/WASM.md index c38c95c..1cd9995 100644 --- a/WASM.md +++ b/WASM.md @@ -1,48 +1,48 @@ -# WhoAmI WebAssembly Documentation - -## Web (Browser) -By default, when WhoAmI is compiled for Wasm32 unknown (neither -wasi or -daku), -WhoAmI links to web-sys and defaults values to browser information: - - - `realname()`: "Anonymous" - - `username()`: "anonymous" - - `lang()`: Browser preferred language list - - `devicename()`: Browser name (Example: "Firefox 110.0") - - `hostname()`: "localhost" - - `platform()`: Host operating system by view of browser (Example: "Linux") - - `distro()`: Host distro by view of browser (Example "Unknown Linux") - - `desktop_env()`: "Web Browser" - - `arch()`: "wasm32" - -## Mock -If you compile WhoAmI with `default-features = false`, WhoAmI will not bind to -web-sys, and will instead return these mock values: - - - `realname()`: "Anonymous" - - `username()`: "anonymous" - - `lang()`: "en-US" - - `devicename()`: "Unknown" - - `hostname()`: "localhost" - - `platform()`: "Unknown" - - `distro()`: "Emulated" - - `desktop_env()`: "Unknown WebAssembly" - - `arch()`: "wasm32" - -## Wasi (Wasite) -Building WhoAmI targeting Wasi will assume the -[wasite](https://ardaku.org/wasite/env_vars.html) environment variables are set, -as Wasi alone does not currently support the functionality WhoAmI requires. - - - `realname()`: `$USER` - - `username()`: `$USER` - - `lang()`: `$LANGS` - - `devicename()`: `$NAME` - - `hostname()`: `$HOSTNAME` - - `platform()`: "Wasite" - - `distro()`: "Unknown wasi" - - `desktop_env()`: "Unknown wasite" - - `arch()`: "wasm32" - -## Daku (Quantii, other Ardaku environments) -WhoAmi will depend on currently unstable portals in the -[Daku](https://ardaku.org/daku/) specification. +# WhoAmI WebAssembly Documentation + +## Web (Browser) +By default, when WhoAmI is compiled for Wasm32 unknown (neither -wasi or -daku), +WhoAmI links to web-sys and defaults values to browser information: + + - `realname()`: "Anonymous" + - `username()`: "anonymous" + - `lang()`: Browser preferred language list + - `devicename()`: Browser name (Example: "Firefox 110.0") + - `hostname()`: "localhost" + - `platform()`: Host operating system by view of browser (Example: "Linux") + - `distro()`: Host distro by view of browser (Example "Unknown Linux") + - `desktop_env()`: "Web Browser" + - `arch()`: "wasm32" + +## Mock +If you compile WhoAmI with `default-features = false`, WhoAmI will not bind to +web-sys, and will instead return these mock values: + + - `realname()`: "Anonymous" + - `username()`: "anonymous" + - `lang()`: "en-US" + - `devicename()`: "Unknown" + - `hostname()`: "localhost" + - `platform()`: "Unknown" + - `distro()`: "Emulated" + - `desktop_env()`: "Unknown WebAssembly" + - `arch()`: "wasm32" + +## Wasi (Wasite) +Building WhoAmI targeting Wasi will assume the +[wasite](https://ardaku.org/wasite/env_vars.html) environment variables are set, +as Wasi alone does not currently support the functionality WhoAmI requires. + + - `realname()`: `$USER` + - `username()`: `$USER` + - `lang()`: `$LANGS` + - `devicename()`: `$NAME` + - `hostname()`: `$HOSTNAME` + - `platform()`: "Wasite" + - `distro()`: "Unknown wasi" + - `desktop_env()`: "Unknown wasite" + - `arch()`: "wasm32" + +## Daku (Quantii, other Ardaku environments) +WhoAmi will depend on currently unstable portals in the +[Daku](https://ardaku.org/daku/) specification. diff --git a/examples/os-strings.rs b/examples/os-strings.rs index abbf5d2..158248d 100644 --- a/examples/os-strings.rs +++ b/examples/os-strings.rs @@ -1,42 +1,42 @@ -fn main() { - println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); - println!(); - println!( - "User's Name whoami::realname_os(): {:?}", - whoami::realname_os() - ); - println!( - "User's Username whoami::username_os(): {:?}", - whoami::username() - ); - println!( - "User's Language whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - ); - println!( - "Device's Pretty Name whoami::devicename_os(): {:?}", - whoami::devicename() - ); - println!( - "Device's Hostname whoami::hostname_os(): {:?}", - whoami::hostname() - ); - println!( - "Device's Platform whoami::platform_os(): {:?}", - whoami::platform() - ); - println!( - "Device's OS Distro whoami::distro_os(): {:?}", - whoami::distro() - ); - println!( - "Device's Desktop Env. whoami::desktop_env(): {:?}", - whoami::desktop_env() - ); - println!( - "Device's CPU Arch whoami::arch(): {:?}", - whoami::arch() - ); -} +fn main() { + println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); + println!(); + println!( + "User's Name whoami::realname_os(): {:?}", + whoami::realname_os() + ); + println!( + "User's Username whoami::username_os(): {:?}", + whoami::username() + ); + println!( + "User's Language whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + ); + println!( + "Device's Pretty Name whoami::devicename_os(): {:?}", + whoami::devicename() + ); + println!( + "Device's Hostname whoami::hostname_os(): {:?}", + whoami::hostname() + ); + println!( + "Device's Platform whoami::platform_os(): {:?}", + whoami::platform() + ); + println!( + "Device's OS Distro whoami::distro_os(): {:?}", + whoami::distro() + ); + println!( + "Device's Desktop Env. whoami::desktop_env(): {:?}", + whoami::desktop_env() + ); + println!( + "Device's CPU Arch whoami::arch(): {:?}", + whoami::arch() + ); +} diff --git a/examples/web/Cargo.toml b/examples/web/Cargo.toml index c552342..2f74f75 100644 --- a/examples/web/Cargo.toml +++ b/examples/web/Cargo.toml @@ -1,36 +1,36 @@ -[package] -name = "whoami_web" -version = "0.1.0" -authors = ["Jeron Aldaron Lau "] -edition = "2021" - -[lib] -crate-type = ["cdylib", "rlib"] - -[features] -default = ["console_error_panic_hook"] - -# The `console_error_panic_hook` crate provides better debugging of panics by -# logging them with `console.error`. This is great for development, but requires -# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for -# code size when deploying. -[dependencies.console_error_panic_hook] -version = "0.1" -optional = true - -# wasm-bindgen lets us export our main function to the javascript that runs the -# web assembly module. -[dependencies.wasm-bindgen] -version = "0.2" - -# The `web-sys` crate lets us log in the web console. -[dependencies.web-sys] -version = "0.3" -features = ["console"] - -# `whoami` - the crate we're testing! -[dependencies.whoami] -path = "../../" - -[profile.release] -opt-level = "s" # Tell `rustc` to optimize for small code size. +[package] +name = "whoami_web" +version = "0.1.0" +authors = ["Jeron Aldaron Lau "] +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[features] +default = ["console_error_panic_hook"] + +# The `console_error_panic_hook` crate provides better debugging of panics by +# logging them with `console.error`. This is great for development, but requires +# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for +# code size when deploying. +[dependencies.console_error_panic_hook] +version = "0.1" +optional = true + +# wasm-bindgen lets us export our main function to the javascript that runs the +# web assembly module. +[dependencies.wasm-bindgen] +version = "0.2" + +# The `web-sys` crate lets us log in the web console. +[dependencies.web-sys] +version = "0.3" +features = ["console"] + +# `whoami` - the crate we're testing! +[dependencies.whoami] +path = "../../" + +[profile.release] +opt-level = "s" # Tell `rustc` to optimize for small code size. diff --git a/examples/web/README.md b/examples/web/README.md index 61d1797..b008fc0 100644 --- a/examples/web/README.md +++ b/examples/web/README.md @@ -1,15 +1,15 @@ -# A Web Example - -## Install `wasm-pack` and `http` -```bash -curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -cargo install https -``` - -## Build & Run Web Server -```bash -wasm-pack build --target web && http . -``` - -Now, open http://localhost:8000/ in your web browser and check the javascript -console. +# A Web Example + +## Install `wasm-pack` and `http` +```bash +curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh +cargo install https +``` + +## Build & Run Web Server +```bash +wasm-pack build --target web && http . +``` + +Now, open http://localhost:8000/ in your web browser and check the javascript +console. diff --git a/examples/web/index.html b/examples/web/index.html index d49a157..b23bac6 100644 --- a/examples/web/index.html +++ b/examples/web/index.html @@ -1,14 +1,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/examples/web/rust-toolchain b/examples/web/rust-toolchain index ec19b69..292fe49 100644 --- a/examples/web/rust-toolchain +++ b/examples/web/rust-toolchain @@ -1,2 +1,2 @@ -[toolchain] -channel = "stable" +[toolchain] +channel = "stable" diff --git a/examples/web/src/lib.rs b/examples/web/src/lib.rs index cc783b8..57f996b 100644 --- a/examples/web/src/lib.rs +++ b/examples/web/src/lib.rs @@ -1,57 +1,57 @@ -use wasm_bindgen::prelude::*; - -fn log(text: String) { - web_sys::console::log_1(&text.into()) -} - -#[wasm_bindgen] -pub fn main() { - // When the `console_error_panic_hook` feature is enabled, we can call the - // `set_panic_hook` function at least once during initialization, and then - // we will get better error messages if our code ever panics. - // - // For more details see - // https://github.com/rustwasm/console_error_panic_hook#readme - #[cfg(feature = "console_error_panic_hook")] - console_error_panic_hook::set_once(); - - // Print out code from regular example. - log(format!( - "User's Name whoami::realname(): {}", - whoami::realname(), - )); - log(format!( - "User's Username whoami::username(): {}", - whoami::username(), - )); - log(format!( - "User's Languages whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - )); - log(format!( - "Device's Pretty Name whoami::devicename(): {}", - whoami::devicename(), - )); - log(format!( - "Device's Hostname whoami::hostname(): {}", - whoami::hostname(), - )); - log(format!( - "Device's Platform whoami::platform(): {}", - whoami::platform(), - )); - log(format!( - "Device's OS Distro whoami::distro(): {}", - whoami::distro(), - )); - log(format!( - "Device's Desktop Env. whoami::desktop_env(): {}", - whoami::desktop_env(), - )); - log(format!( - "Device's CPU Arch whoami::arch(): {}", - whoami::arch(), - )); -} +use wasm_bindgen::prelude::*; + +fn log(text: String) { + web_sys::console::log_1(&text.into()) +} + +#[wasm_bindgen] +pub fn main() { + // When the `console_error_panic_hook` feature is enabled, we can call the + // `set_panic_hook` function at least once during initialization, and then + // we will get better error messages if our code ever panics. + // + // For more details see + // https://github.com/rustwasm/console_error_panic_hook#readme + #[cfg(feature = "console_error_panic_hook")] + console_error_panic_hook::set_once(); + + // Print out code from regular example. + log(format!( + "User's Name whoami::realname(): {}", + whoami::realname(), + )); + log(format!( + "User's Username whoami::username(): {}", + whoami::username(), + )); + log(format!( + "User's Languages whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + )); + log(format!( + "Device's Pretty Name whoami::devicename(): {}", + whoami::devicename(), + )); + log(format!( + "Device's Hostname whoami::hostname(): {}", + whoami::hostname(), + )); + log(format!( + "Device's Platform whoami::platform(): {}", + whoami::platform(), + )); + log(format!( + "Device's OS Distro whoami::distro(): {}", + whoami::distro(), + )); + log(format!( + "Device's Desktop Env. whoami::desktop_env(): {}", + whoami::desktop_env(), + )); + log(format!( + "Device's CPU Arch whoami::arch(): {}", + whoami::arch(), + )); +} diff --git a/examples/whoami-demo.rs b/examples/whoami-demo.rs index d5dd518..3472fd3 100644 --- a/examples/whoami-demo.rs +++ b/examples/whoami-demo.rs @@ -1,42 +1,42 @@ -fn main() { - println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); - println!(); - println!( - "User's Name whoami::realname(): {}", - whoami::realname(), - ); - println!( - "User's Username whoami::username(): {}", - whoami::username(), - ); - println!( - "User's Language whoami::lang(): {:?}", - whoami::langs() - .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) - .collect::>(), - ); - println!( - "Device's Pretty Name whoami::devicename(): {}", - whoami::devicename(), - ); - println!( - "Device's Hostname whoami::hostname(): {}", - whoami::hostname(), - ); - println!( - "Device's Platform whoami::platform(): {}", - whoami::platform(), - ); - println!( - "Device's OS Distro whoami::distro(): {}", - whoami::distro(), - ); - println!( - "Device's Desktop Env. whoami::desktop_env(): {}", - whoami::desktop_env(), - ); - println!( - "Device's CPU Arch whoami::arch(): {}", - whoami::arch(), - ); -} +fn main() { + println!("WhoAmI {}", env!("CARGO_PKG_VERSION")); + println!(); + println!( + "User's Name whoami::realname(): {}", + whoami::realname(), + ); + println!( + "User's Username whoami::username(): {}", + whoami::username(), + ); + println!( + "User's Language whoami::lang(): {:?}", + whoami::langs() + .map(|l| l.map(|l| l.to_string()).unwrap_or("??".to_string())) + .collect::>(), + ); + println!( + "Device's Pretty Name whoami::devicename(): {}", + whoami::devicename(), + ); + println!( + "Device's Hostname whoami::hostname(): {}", + whoami::hostname(), + ); + println!( + "Device's Platform whoami::platform(): {}", + whoami::platform(), + ); + println!( + "Device's OS Distro whoami::distro(): {}", + whoami::distro(), + ); + println!( + "Device's Desktop Env. whoami::desktop_env(): {}", + whoami::desktop_env(), + ); + println!( + "Device's CPU Arch whoami::arch(): {}", + whoami::arch(), + ); +} diff --git a/res/icon.svg b/res/icon.svg index 6772500..71fc460 100644 --- a/res/icon.svg +++ b/res/icon.svg @@ -1,108 +1,108 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/rust-toolchain b/rust-toolchain index 8395338..aacef61 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,2 +1,2 @@ -[toolchain] -channel = "1.40.0" +[toolchain] +channel = "1.40.0" diff --git a/src/disp.rs b/src/disp.rs index 5964369..ce7bfca 100644 --- a/src/disp.rs +++ b/src/disp.rs @@ -1,250 +1,248 @@ -use ansi_term::Colour; - -pub fn display_windows() -> &'static str { - r#" - .oodMMMM - .oodMMMMMMMMMMMMM - ..oodMMM MMMMMMMMMMMMMMMMMMM - oodMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM .----------------. .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | - | | _____ _____ | || | _____ | || | ____ _____ | || | ________ | || | ____ | || | _____ _____ | || | _______ | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | ||_ _||_ _|| || | |_ _| | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | || ||_ _||_ _|| || | / ___ | | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | | /\ | | | || | | | | || | | \ | | | || | | | `. \ | || | / .--. \ | || | | | /\ | | | || | | (__ \_| | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | |/ \| | | || | | | | || | | |\ \| | | || | | | | | | || | | | | | | || | | |/ \| | | || | '.___`-. | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | /\ | | || | _| |_ | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | || | | /\ | | || | |`\____) | | | - MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | |__/ \__| | || | |_____| | || ||_____|\____| | || | |________.' | || | `.____.' | || | |__/ \__| | || | |_______.' | | - `^^^^^^MMMMMMM MMMMMMMMMMMMMMMMMMM | | | || | | || | | || | | || | | || | | || | | | - ````^^^^ ^^MMMMMMMMMMMMMMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - ````^^^^^^MMMM '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' -"# -} - -pub fn display_bsd() -> &'static str { - r#" - , , - /( )` - \ \___ / | - /- _ `-/ ' - (/\/ \ \ /\ - / / | ` \ - O O ) / | - `-^--'`< ' - (_.) _ ) / .----------------. .----------------. .----------------. - `.___/` / | .--------------. || .--------------. || .--------------. | - `-----' / | | ______ | || | _______ | || | ________ | | - <----. __ / __ \ | | |_ _ \ | || | / ___ | | || | |_ ___ `. | | - <----|====O)))==) \) /==== | | | |_) | | || | | (__ \_| | || | | | `. \ | | - <----' `--' `.__,' \ | | | __'. | || | '.___`-. | || | | | | | | | - | | | | _| |__) | | || | |`\____) | | || | _| |___.' / | | - \ / | | |_______/ | || | |_______.' | || | |________.' | | - ______( (_ / \______ | | | || | | || | | | - ,' ,-----' | \ | '--------------' || '--------------' || '--------------' | - `--{__________) \/ '----------------' '----------------' '----------------' -"# -} - -pub fn display_macos() -> &'static str{ - r#" - ,xNMM. - .OMMMMo - lMM" - .;loddo:. .olloddol;. - cKMMMMMMMMMMNWMMMMMMMMMM0: - .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. .----------------. .----------------. - XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | -;MMMMMMMMMMMMMMMMMMMMMMMM: | | ____ ____ | || | __ | || | ______ | || | ____ | || | _______ | | -:MMMMMMMMMMMMMMMMMMMMMMMM: | ||_ \ / _|| || | / \ | || | .' ___ | | || | .' `. | || | / ___ | | | -.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | \/ | | || | / /\ \ | || | / .' \_| | || | / .--. \ | || | | (__ \_| | | - kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | |\ /| | | || | / ____ \ | || | | | | || | | | | | | || | '.___`-. | | - 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_\/_| |_ | || | _/ / \ \_ | || | \ `.___.'\ | || | \ `--' / | || | |`\____) | | | - 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | ||_____||_____|| || ||____| |____|| || | `._____.' | || | `.____.' | || | |_______.' | | - kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | || | | || | | | - ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - "cooc*" "*coo' '----------------' '----------------' '----------------' '----------------' '----------------' -"# -} - -pub fn display_illumos() -> &'static str { - r#" -' Tw - `h||hnN - \P|||I$N - `P|||$IK, - `%wb$$IPK, - .*b|I$PPKp - `TP@|$KPPKp - `%wwI@K$PPPKw ,pKKKKm>. - "Tb@|$KPPPPKp pPPPK" - "TK@@@@K$PPPPKp,,bPPK - -wppP$$$$PPPPPPPPPPb - ,,pbP$$PPPPPPPPPP - ,,$pPPPPPPPPPPP .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. - ,pKKPPPPPPPPPL | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | - -<4PPPPPPPP | | _____ | || | _____ | || | _____ | || | _____ _____ | || | ____ ____ | || | ____ | || | _______ | | - PPPPPP` | | |_ _| | || | |_ _| | || | |_ _| | || ||_ _||_ _|| || ||_ \ / _|| || | .' `. | || | / ___ | | | - /KPPPM/ | | | | | || | | | | || | | | | || | | | | | | || | | \/ | | || | / .--. \ | || | | (__ \_| | | - ,pKPPPM` | | | | | || | | | _ | || | | | _ | || | | ' ' | | || | | |\ /| | | || | | | | | | || | '.___`-. | | - ,,pKK$PPM | | _| |_ | || | _| |__/ | | || | _| |__/ | | || | \ `--' / | || | _| |_\/_| |_ | || | \ `--' / | || | |`\____) | | | - '''''qK9K | | |_____| | || | |________| | || | |________| | || | `.__.' | || ||_____||_____|| || | `.____.' | || | |_______.' | | - ,p#M",#" | | | || | | || | | || | | || | | || | | || | | | - `` ,pM` | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - '` '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' - "# -} - -pub fn display_ios() -> &'static str { - r#" - ,xNMM. - .OMMMMo - lMM" - .;loddo:. .olloddol;. - cKMMMMMMMMMMNWMMMMMMMMMM0: - .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. - XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. | -;MMMMMMMMMMMMMMMMMMMMMMMM: | | _____ | || | ____ | || | _______ | | -:MMMMMMMMMMMMMMMMMMMMMMMM: | | |_ _| | || | .' `. | || | / ___ | | | -.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | | | || | / .--. \ | || | | (__ \_| | | - kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | | | || | | | | | | || | '.___`-. | | - 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_ | || | \ `--' / | || | |`\____) | | | - 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | | |_____| | || | `.____.' | || | |_______.' | | - kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | | - ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' | - "cooc*" "*coo' '----------------' '----------------' '----------------' -"# -} - -pub fn display_android() -> &'static str { - r#" - -o o- - +hydNNNNdyh+ - +mMMMMMMMMMMMMm+ - `dMMm:NMMMMMMN:mMMd` - hMMMMMMMMMMMMMMMMMMh - .. yyyyyyyyyyyyyyyyyyyy .. -.mMMm`MMMMMMMMMMMMMMMMMMMM`mMMm. -:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. .----------------. -:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | -:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | __ | || | ____ _____ | || | ________ | || | _______ | || | ____ | || | _____ | || | ________ | | -:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | / \ | || ||_ \|_ _| | || | |_ ___ `. | || | |_ __ \ | || | .' `. | || | |_ _| | || | |_ ___ `. | | --MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM- | | / /\ \ | || | | \ | | | || | | | `. \ | || | | |__) | | || | / .--. \ | || | | | | || | | | `. \ | | - +yy+ MMMMMMMMMMMMMMMMMMMM +yy+ | | / ____ \ | || | | |\ \| | | || | | | | | | || | | __ / | || | | | | | | || | | | | || | | | | | | | - mMMMMMMMMMMMMMMMMMMm | | _/ / \ \_ | || | _| |_\ |_ | || | _| |___.' / | || | _| | \ \_ | || | \ `--' / | || | _| |_ | || | _| |___.' / | | - `/++MMMMh++hMMMM++/` | ||____| |____|| || ||_____|\____| | || | |________.' | || | |____| |___| | || | `.____.' | || | |_____| | || | |________.' | | - MMMMo oMMMM | | | || | | || | | || | | || | | || | | || | | | - MMMMo oMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - oNMm- -mMNs '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' -"# -} - -pub fn display_nintendo() -> &'static str { - r#" - .-----------------. .----------------. .-----------------. .----------------. .----------------. .-----------------. .----------------. .----------------. - | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | - | | ____ _____ | || | _____ | || | ____ _____ | || | _________ | || | _________ | || | ____ _____ | || | ________ | || | ____ | | - | ||_ \|_ _| | || | |_ _| | || ||_ \|_ _| | || | | _ _ | | || | |_ ___ | | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | | -⠀⠀⠀⣀⣤⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣤⡀⠀⠀⠀ | | | \ | | | || | | | | || | | \ | | | || | |_/ | | \_| | || | | |_ \_| | || | | \ | | | || | | | `. \ | || | / .--. \ | | -⠀⣠⣾⡿⠛⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠻⣿⣷⡀ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | |⠀ -⢰⣿⡏⠀⠀ ⣶⣶⣆⠀⠀⣶⣶⠀⢰⣶⡆⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣶⣶⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⡄ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | | -⣿⣿⠀⠀⠀⠀⣿⣿⢿⣧⡀⣿⣿⠀⢰⣶⡆⢰⣶⣦⠴⢶⣦⡄⠛⣿⣿⠛⢀⣤⡖⠒⣶⣄⠀⣴⣶⡦⠶⣶⣦⡀⢀⣴⡶⠶⣿⣿⠀⢠⣴⡖⠒⣦⡄⠀⠀⠸⣿⡇ | | _| |_\ |_ | || | _| |_ | || | _| |_\ |_ | || | _| |_ | || | _| |___/ | | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | | -⣿⣿⠀⠀⠀⠀⣿⣿⠀⢻⣿⣿⣿⠀⢸⣿⡇⢸⣿⡏⠀⠈⣿⣿⠀⣿⣿⠀⢾⣿⡟⠛⠛⠛⠂⣿⣿⡇⠀⢸⣿⡇⢸⣿⡇⠀⣿⣿⠀⣿⣿⠀⠀⣿⣿⠀⠀⢠⣿⡇ | ||_____|\____| | || | |_____| | || ||_____|\____| | || | |_____| | || | |_________| | || ||_____|\____| | || | |________.' | || | `.____.' | | -⠸⣿⣇⠀⠀⠀⠿⠿⠀⠀⠹⠿⠿⠀⠸⠿⠇⠸⠿⠇⠀⠠⠿⠿⠀⠿⠿⠀⠈⠻⠧⠤⠿⠟⠀⠿⠿⠇⠀⠸⠿⠇⠘⠿⣧⡤⠿⠿⠀⠘⠿⠧⠴⠿⠋⠀⢀⣾⣿⠃ | | | || | | || | | || | | || | | || | | || | | || | | | -⠀⠙⢿⣷⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣴⣿⡿⠁⠀ | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | -⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠉ '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' - "# -} -pub fn display_xbox() -> &'static str { - r#" -⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣶⣶⣶⣶⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⡀⠀⠈⠉⠛⠿⣿⣿⣿⣿⠿⠛⠉⠁⠀⢀⠀⠀⠀⠀⠀ -⠀⠀⠀⣴⣿⣿⣿⣶⣄⡀⠀⠈⠙⠋⠁⠀⢀⣠⣶⣿⣿⣿⣦⠀⠀⠀ .----------------. .----------------. .----------------. .----------------. -⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠂⠀⠀⠀⠀⠐⢿⣿⣿⣿⣿⣿⣿⣷⡀⠀ | .--------------. || .--------------. || .--------------. || .--------------. | -⠀⣾⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⢀⡀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⣷⠀ | | ____ ____ | || | ______ | || | ____ | || | ____ ____ | | -⢠⣿⣿⣿⣿⣿⡟⠁⠀⠀⢀⣴⣿⣿⣦⡀⠀⠀⠈⢻⣿⣿⣿⣿⣿⡄ | | |_ _||_ _| | || | |_ _ \ | || | .' `. | || | |_ _||_ _| | | -⢸⣿⣿⣿⣿⠏⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠹⣿⣿⣿⣿⡇ | | \ \ / / | || | | |_) | | || | / .--. \ | || | \ \ / / | | -⠘⣿⣿⣿⠏⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠹⣿⣿⣿⠃ | | > `' < | || | | __'. | || | | | | | | || | > `' < | | -⠀⢿⣿⡟⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⢻⣿⡿⠀ | | _/ /'`\ \_ | || | _| |__) | | || | \ `--' / | || | _/ /'`\ \_ | | -⠀⠈⢿⡇⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢸⡿⠁⠀ | | |____||____| | || | |_______/ | || | `.____.' | || | |____||____| | | -⠀⠀⠀⠃⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠘⠀⠀ | | | || | | || | | || | | | -⠀⠀⠀⠀⠈⠛⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠁⠀⠀⠀⠀ | '--------------' || '--------------' || '--------------' || '--------------' | -⠀⠀⠀⠀⠀⠀⠀⠈⠙⠛⠛⠿⠿⠿⠿⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' '----------------' '----------------' - "# -} - -pub fn display_playstation() -> &'static str { - r#" -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣷⣶⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠿⣿⣷⣶⣄⠀⠀⠀⠀⠀ .----------------. .----------------. -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀ | .--------------. || .--------------. | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀ | | ______ | || | _______ | | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀ | | |_ __ \ | || | / ___ | | | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀ | | | |__) | | || | | (__ \_| | | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⠇⠀⠀⠀⠀ | | | ___/ | || | '.___`-. | | -⠀⠀⠀⠀⠀⠀⠀⣀⣤⠀⣿⣿⣿⣿⡇⠀⠈⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ | | _| |_ | || | |`\____) | | | -⠀⢀⣠⣤⣶⣾⣿⣿⡿⠀⣿⣿⣿⣿⡇⠀⢰⣶⣿⣿⣿⠿⠿⢿⣶⣦⣤⡀ | | |_____| | || | |_______.' | | -⢰⣿⣿⣿⡿⠛⠉⢀⣀⠀⣿⣿⣿⣿⡇⠀⠘⠋⠉⠀⣀⣠⣴⣾⣿⣿⣿⠇ | | | || | | | -⠈⠻⠿⣿⣿⣿⣿⣿⠿⠀⣿⣿⣿⣿⡇⠀⢠⣶⣾⣿⣿⡿⠿⠟⠋⠉⠀⠀ | '--------------' || '--------------' | -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⢿⡇⠀⠸⠟⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' - "# -} - -pub fn display_redox() -> &'static str { - r#" - ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ - ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ - ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ - ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ - ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▐░▌ - ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ - ▐░█▀▀▀▀█░█▀▀ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌░▌ - ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ - ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ - ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ - ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ - "# -} - -pub fn display_fuchsia() -> &'static str { - r#" - ▄████ ▄█▄ ▄ █ ▄▄▄▄▄ ▄█ ██ - █▀ █▀ ▀▄ █ █ █ ▀▄ ██ █ █ - █▀▀ █ █ █ ▀ ██▀▀█ ▄ ▀▀▀▀▄ ██ █▄▄█ - █ █ █ █▄ ▄▀ █ █ ▀▄▄▄▄▀ ▐█ █ █ - █ █▄ ▄█ ▀███▀ █ ▐ █ - ▀ ▀▀▀ ▀ █ - ▀ - "# -} - -pub fn display_linux() -> &'static str { - r#" - .88888888:. - 88888888.88888. - .8888888888888888. - 888888888888888888 - 88' _`88'_ `88888 - 88 88 88 88 88888 - 88_88_::_88_:88888 - 88:::,::,:::::8888 - 88`:::::::::'`8888 - .88 `::::' 8:88. - 8888 `8:888. - .8888' `888888. - .8888:.. .::. ...:'8888888:. - .8888.' :' `'::`88:88888 - .8888 ' `.888:8888. - 888:8 . 888:88888 .----------------. .----------------. .-----------------. .----------------. .----------------. - .888:88 .: 888:88888: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | - 8888888. :: 88:888888 | | _____ | || | _____ | || | ____ _____ | || | _____ _____ | || | ____ ____ | | - `.::.888. :: .88888888 | | |_ _| | || | |_ _| | || ||_ \|_ _| | || ||_ _||_ _|| || | |_ _||_ _| | | - .::::::.888. :: :::`8888'.:. | | | | | || | | | | || | | \ | | | || | | | | | | || | \ \ / / | | - ::::::::::.888 ' .:::::::::::: | | | | _ | || | | | | || | | |\ \| | | || | | ' ' | | || | > `' < | | - ::::::::::::.8 ' .:8::::::::::::. | | _| |__/ | | || | _| |_ | || | _| |_\ |_ | || | \ `--' / | || | _/ /'`\ \_ | | - .::::::::::::::. .:888::::::::::::: | | |________| | || | |_____| | || ||_____|\____| | || | `.__.' | || | |____||____| | | - :::::::::::::::88:.__..:88888:::::::::::' | | | || | | || | | || | | || | | | - `'.:::::::::::88888888888.88:::::::::' | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | - `':::_:' -- '' -'-' `':_::::'` '----------------' '----------------' '----------------' '----------------' '----------------' -"# -} +pub fn display_windows() -> &'static str { + r#" + .oodMMMM + .oodMMMMMMMMMMMMM + ..oodMMM MMMMMMMMMMMMMMMMMMM + oodMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM .----------------. .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + | | _____ _____ | || | _____ | || | ____ _____ | || | ________ | || | ____ | || | _____ _____ | || | _______ | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | ||_ _||_ _|| || | |_ _| | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | || ||_ _||_ _|| || | / ___ | | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | | /\ | | | || | | | | || | | \ | | | || | | | `. \ | || | / .--. \ | || | | | /\ | | | || | | (__ \_| | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | |/ \| | | || | | | | || | | |\ \| | | || | | | | | | || | | | | | | || | | |/ \| | | || | '.___`-. | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | | /\ | | || | _| |_ | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | || | | /\ | | || | |`\____) | | | + MMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMMM | | |__/ \__| | || | |_____| | || ||_____|\____| | || | |________.' | || | `.____.' | || | |__/ \__| | || | |_______.' | | + `^^^^^^MMMMMMM MMMMMMMMMMMMMMMMMMM | | | || | | || | | || | | || | | || | | || | | | + ````^^^^ ^^MMMMMMMMMMMMMMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + ````^^^^^^MMMM '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_bsd() -> &'static str { + r#" + , , + /( )` + \ \___ / | + /- _ `-/ ' + (/\/ \ \ /\ + / / | ` \ + O O ) / | + `-^--'`< ' + (_.) _ ) / .----------------. .----------------. .----------------. + `.___/` / | .--------------. || .--------------. || .--------------. | + `-----' / | | ______ | || | _______ | || | ________ | | + <----. __ / __ \ | | |_ _ \ | || | / ___ | | || | |_ ___ `. | | + <----|====O)))==) \) /==== | | | |_) | | || | | (__ \_| | || | | | `. \ | | + <----' `--' `.__,' \ | | | __'. | || | '.___`-. | || | | | | | | | + | | | | _| |__) | | || | |`\____) | | || | _| |___.' / | | + \ / | | |_______/ | || | |_______.' | || | |________.' | | + ______( (_ / \______ | | | || | | || | | | + ,' ,-----' | \ | '--------------' || '--------------' || '--------------' | + `--{__________) \/ '----------------' '----------------' '----------------' +"# +} + +pub fn display_macos() -> &'static str{ + r#" + ,xNMM. + .OMMMMo + lMM" + .;loddo:. .olloddol;. + cKMMMMMMMMMMNWMMMMMMMMMM0: + .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. .----------------. .----------------. + XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | +;MMMMMMMMMMMMMMMMMMMMMMMM: | | ____ ____ | || | __ | || | ______ | || | ____ | || | _______ | | +:MMMMMMMMMMMMMMMMMMMMMMMM: | ||_ \ / _|| || | / \ | || | .' ___ | | || | .' `. | || | / ___ | | | +.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | \/ | | || | / /\ \ | || | / .' \_| | || | / .--. \ | || | | (__ \_| | | + kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | |\ /| | | || | / ____ \ | || | | | | || | | | | | | || | '.___`-. | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_\/_| |_ | || | _/ / \ \_ | || | \ `.___.'\ | || | \ `--' / | || | |`\____) | | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | ||_____||_____|| || ||____| |____|| || | `._____.' | || | `.____.' | || | |_______.' | | + kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | || | | || | | | + ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + "cooc*" "*coo' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_illumos() -> &'static str { + r#" +' Tw + `h||hnN + \P|||I$N + `P|||$IK, + `%wb$$IPK, + .*b|I$PPKp + `TP@|$KPPKp + `%wwI@K$PPPKw ,pKKKKm>. + "Tb@|$KPPPPKp pPPPK" + "TK@@@@K$PPPPKp,,bPPK + -wppP$$$$PPPPPPPPPPb + ,,pbP$$PPPPPPPPPP + ,,$pPPPPPPPPPPP .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. + ,pKKPPPPPPPPPL | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + -<4PPPPPPPP | | _____ | || | _____ | || | _____ | || | _____ _____ | || | ____ ____ | || | ____ | || | _______ | | + PPPPPP` | | |_ _| | || | |_ _| | || | |_ _| | || ||_ _||_ _|| || ||_ \ / _|| || | .' `. | || | / ___ | | | + /KPPPM/ | | | | | || | | | | || | | | | || | | | | | | || | | \/ | | || | / .--. \ | || | | (__ \_| | | + ,pKPPPM` | | | | | || | | | _ | || | | | _ | || | | ' ' | | || | | |\ /| | | || | | | | | | || | '.___`-. | | + ,,pKK$PPM | | _| |_ | || | _| |__/ | | || | _| |__/ | | || | \ `--' / | || | _| |_\/_| |_ | || | \ `--' / | || | |`\____) | | | + '''''qK9K | | |_____| | || | |________| | || | |________| | || | `.__.' | || ||_____||_____|| || | `.____.' | || | |_______.' | | + ,p#M",#" | | | || | | || | | || | | || | | || | | || | | | + `` ,pM` | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + '` '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' + "# +} + +pub fn display_ios() -> &'static str { + r#" + ,xNMM. + .OMMMMo + lMM" + .;loddo:. .olloddol;. + cKMMMMMMMMMMNWMMMMMMMMMM0: + .KMMMMMMMMMMMMMMMMMMMMMMMWd. .----------------. .----------------. .----------------. + XMMMMMMMMMMMMMMMMMMMMMMMX. | .--------------. || .--------------. || .--------------. | +;MMMMMMMMMMMMMMMMMMMMMMMM: | | _____ | || | ____ | || | _______ | | +:MMMMMMMMMMMMMMMMMMMMMMMM: | | |_ _| | || | .' `. | || | / ___ | | | +.MMMMMMMMMMMMMMMMMMMMMMMMX. | | | | | || | / .--. \ | || | | (__ \_| | | + kMMMMMMMMMMMMMMMMMMMMMMMMWd. | | | | | || | | | | | | || | '.___`-. | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMMMk | | _| |_ | || | \ `--' / | || | |`\____) | | | + 'XMMMMMMMMMMMMMMMMMMMMMMMMK. | | |_____| | || | `.____.' | || | |_______.' | | + kMMMMMMMMMMMMMMMMMMMMMMd | | | || | | || | | | + ;KMMMMMMMWXXWMMMMMMMk. | '--------------' || '--------------' || '--------------' | + "cooc*" "*coo' '----------------' '----------------' '----------------' +"# +} + +pub fn display_android() -> &'static str { + r#" + -o o- + +hydNNNNdyh+ + +mMMMMMMMMMMMMm+ + `dMMm:NMMMMMMN:mMMd` + hMMMMMMMMMMMMMMMMMMh + .. yyyyyyyyyyyyyyyyyyyy .. +.mMMm`MMMMMMMMMMMMMMMMMMMM`mMMm. +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: .----------------. .-----------------. .----------------. .----------------. .----------------. .----------------. .----------------. +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | __ | || | ____ _____ | || | ________ | || | _______ | || | ____ | || | _____ | || | ________ | | +:MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM: | | / \ | || ||_ \|_ _| | || | |_ ___ `. | || | |_ __ \ | || | .' `. | || | |_ _| | || | |_ ___ `. | | +-MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM- | | / /\ \ | || | | \ | | | || | | | `. \ | || | | |__) | | || | / .--. \ | || | | | | || | | | `. \ | | + +yy+ MMMMMMMMMMMMMMMMMMMM +yy+ | | / ____ \ | || | | |\ \| | | || | | | | | | || | | __ / | || | | | | | | || | | | | || | | | | | | | + mMMMMMMMMMMMMMMMMMMm | | _/ / \ \_ | || | _| |_\ |_ | || | _| |___.' / | || | _| | \ \_ | || | \ `--' / | || | _| |_ | || | _| |___.' / | | + `/++MMMMh++hMMMM++/` | ||____| |____|| || ||_____|\____| | || | |________.' | || | |____| |___| | || | `.____.' | || | |_____| | || | |________.' | | + MMMMo oMMMM | | | || | | || | | || | | || | | || | | || | | | + MMMMo oMMMM | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + oNMm- -mMNs '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} + +pub fn display_nintendo() -> &'static str { + r#" + .-----------------. .----------------. .-----------------. .----------------. .----------------. .-----------------. .----------------. .----------------. + | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + | | ____ _____ | || | _____ | || | ____ _____ | || | _________ | || | _________ | || | ____ _____ | || | ________ | || | ____ | | + | ||_ \|_ _| | || | |_ _| | || ||_ \|_ _| | || | | _ _ | | || | |_ ___ | | || ||_ \|_ _| | || | |_ ___ `. | || | .' `. | | +⠀⠀⠀⣀⣤⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣶⣤⡀⠀⠀⠀ | | | \ | | | || | | | | || | | \ | | | || | |_/ | | \_| | || | | |_ \_| | || | | \ | | | || | | | `. \ | || | / .--. \ | | +⠀⣠⣾⡿⠛⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠉⠻⣿⣷⡀ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | |⠀ +⢰⣿⡏⠀⠀ ⣶⣶⣆⠀⠀⣶⣶⠀⢰⣶⡆⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⣶⣶⠀⠀⠀⠀⠀⠀⠀⠀⠈⢿⣿⡄ | | | |\ \| | | || | | | | || | | |\ \| | | || | | | | || | | _| _ | || | | |\ \| | | || | | | | | | || | | | | | | | +⣿⣿⠀⠀⠀⠀⣿⣿⢿⣧⡀⣿⣿⠀⢰⣶⡆⢰⣶⣦⠴⢶⣦⡄⠛⣿⣿⠛⢀⣤⡖⠒⣶⣄⠀⣴⣶⡦⠶⣶⣦⡀⢀⣴⡶⠶⣿⣿⠀⢠⣴⡖⠒⣦⡄⠀⠀⠸⣿⡇ | | _| |_\ |_ | || | _| |_ | || | _| |_\ |_ | || | _| |_ | || | _| |___/ | | || | _| |_\ |_ | || | _| |___.' / | || | \ `--' / | | +⣿⣿⠀⠀⠀⠀⣿⣿⠀⢻⣿⣿⣿⠀⢸⣿⡇⢸⣿⡏⠀⠈⣿⣿⠀⣿⣿⠀⢾⣿⡟⠛⠛⠛⠂⣿⣿⡇⠀⢸⣿⡇⢸⣿⡇⠀⣿⣿⠀⣿⣿⠀⠀⣿⣿⠀⠀⢠⣿⡇ | ||_____|\____| | || | |_____| | || ||_____|\____| | || | |_____| | || | |_________| | || ||_____|\____| | || | |________.' | || | `.____.' | | +⠸⣿⣇⠀⠀⠀⠿⠿⠀⠀⠹⠿⠿⠀⠸⠿⠇⠸⠿⠇⠀⠠⠿⠿⠀⠿⠿⠀⠈⠻⠧⠤⠿⠟⠀⠿⠿⠇⠀⠸⠿⠇⠘⠿⣧⡤⠿⠿⠀⠘⠿⠧⠴⠿⠋⠀⢀⣾⣿⠃ | | | || | | || | | || | | || | | || | | || | | || | | | +⠀⠙⢿⣷⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⣴⣿⡿⠁⠀ | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | +⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠉ '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' + "# +} +pub fn display_xbox() -> &'static str { + r#" +⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣶⣶⣶⣶⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⡀⠀⠈⠉⠛⠿⣿⣿⣿⣿⠿⠛⠉⠁⠀⢀⠀⠀⠀⠀⠀ +⠀⠀⠀⣴⣿⣿⣿⣶⣄⡀⠀⠈⠙⠋⠁⠀⢀⣠⣶⣿⣿⣿⣦⠀⠀⠀ .----------------. .----------------. .----------------. .----------------. +⠀⢀⣾⣿⣿⣿⣿⣿⣿⡿⠂⠀⠀⠀⠀⠐⢿⣿⣿⣿⣿⣿⣿⣷⡀⠀ | .--------------. || .--------------. || .--------------. || .--------------. | +⠀⣾⣿⣿⣿⣿⣿⣿⠋⠀⠀⠀⢀⡀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⣷⠀ | | ____ ____ | || | ______ | || | ____ | || | ____ ____ | | +⢠⣿⣿⣿⣿⣿⡟⠁⠀⠀⢀⣴⣿⣿⣦⡀⠀⠀⠈⢻⣿⣿⣿⣿⣿⡄ | | |_ _||_ _| | || | |_ _ \ | || | .' `. | || | |_ _||_ _| | | +⢸⣿⣿⣿⣿⠏⠀⠀⢀⣴⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠹⣿⣿⣿⣿⡇ | | \ \ / / | || | | |_) | | || | / .--. \ | || | \ \ / / | | +⠘⣿⣿⣿⠏⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠹⣿⣿⣿⠃ | | > `' < | || | | __'. | || | | | | | | || | > `' < | | +⠀⢿⣿⡟⠀⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⡀⠀⢻⣿⡿⠀ | | _/ /'`\ \_ | || | _| |__) | | || | \ `--' / | || | _/ /'`\ \_ | | +⠀⠈⢿⡇⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢸⡿⠁⠀ | | |____||____| | || | |_______/ | || | `.____.' | || | |____||____| | | +⠀⠀⠀⠃⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠘⠀⠀ | | | || | | || | | || | | | +⠀⠀⠀⠀⠈⠛⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠁⠀⠀⠀⠀ | '--------------' || '--------------' || '--------------' || '--------------' | +⠀⠀⠀⠀⠀⠀⠀⠈⠙⠛⠛⠿⠿⠿⠿⠛⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' '----------------' '----------------' + "# +} + +pub fn display_playstation() -> &'static str { + r#" +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣷⣶⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⠿⣿⣷⣶⣄⠀⠀⠀⠀⠀ .----------------. .----------------. +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀ | .--------------. || .--------------. | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀ | | ______ | || | _______ | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀ | | |_ __ \ | || | / ___ | | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⡿⠀⠀⠀⠀⠀⠀ | | | |__) | | || | | (__ \_| | | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡇⠀⢸⣿⣿⣿⣿⠇⠀⠀⠀⠀ | | | ___/ | || | '.___`-. | | +⠀⠀⠀⠀⠀⠀⠀⣀⣤⠀⣿⣿⣿⣿⡇⠀⠈⠉⠉⠉⠁⠀⠀⠀⠀⠀⠀⠀ | | _| |_ | || | |`\____) | | | +⠀⢀⣠⣤⣶⣾⣿⣿⡿⠀⣿⣿⣿⣿⡇⠀⢰⣶⣿⣿⣿⠿⠿⢿⣶⣦⣤⡀ | | |_____| | || | |_______.' | | +⢰⣿⣿⣿⡿⠛⠉⢀⣀⠀⣿⣿⣿⣿⡇⠀⠘⠋⠉⠀⣀⣠⣴⣾⣿⣿⣿⠇ | | | || | | | +⠈⠻⠿⣿⣿⣿⣿⣿⠿⠀⣿⣿⣿⣿⡇⠀⢠⣶⣾⣿⣿⡿⠿⠟⠋⠉⠀⠀ | '--------------' || '--------------' | +⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠛⠿⢿⡇⠀⠸⠟⠛⠋⠁⠀⠀⠀⠀⠀⠀⠀ '----------------' '----------------' + "# +} + +pub fn display_redox() -> &'static str { + r#" + ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ + ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ + ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀▀▀ ▐░█▀▀▀▀▀▀▀█░▌▐░█▀▀▀▀▀▀▀█░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄▄▄ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▐░▌ + ▐░░░░░░░░░░░▌▐░░░░░░░░░░░▌▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ + ▐░█▀▀▀▀█░█▀▀ ▐░█▀▀▀▀▀▀▀▀▀ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌░▌ + ▐░▌ ▐░▌ ▐░▌ ▐░▌ ▐░▌▐░▌ ▐░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌ ▐░█▄▄▄▄▄▄▄▄▄ ▐░█▄▄▄▄▄▄▄█░▌▐░█▄▄▄▄▄▄▄█░▌ ▐░▌ ▐░▌ + ▐░▌ ▐░▌▐░░░░░░░░░░░▌▐░░░░░░░░░░▌ ▐░░░░░░░░░░░▌▐░▌ ▐░▌ + ▀ ▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀ + "# +} + +pub fn display_fuchsia() -> &'static str { + r#" + ▄████ ▄█▄ ▄ █ ▄▄▄▄▄ ▄█ ██ + █▀ █▀ ▀▄ █ █ █ ▀▄ ██ █ █ + █▀▀ █ █ █ ▀ ██▀▀█ ▄ ▀▀▀▀▄ ██ █▄▄█ + █ █ █ █▄ ▄▀ █ █ ▀▄▄▄▄▀ ▐█ █ █ + █ █▄ ▄█ ▀███▀ █ ▐ █ + ▀ ▀▀▀ ▀ █ + ▀ + "# +} + +pub fn display_linux() -> &'static str { + r#" + .88888888:. + 88888888.88888. + .8888888888888888. + 888888888888888888 + 88' _`88'_ `88888 + 88 88 88 88 88888 + 88_88_::_88_:88888 + 88:::,::,:::::8888 + 88`:::::::::'`8888 + .88 `::::' 8:88. + 8888 `8:888. + .8888' `888888. + .8888:.. .::. ...:'8888888:. + .8888.' :' `'::`88:88888 + .8888 ' `.888:8888. + 888:8 . 888:88888 .----------------. .----------------. .-----------------. .----------------. .----------------. + .888:88 .: 888:88888: | .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | + 8888888. :: 88:888888 | | _____ | || | _____ | || | ____ _____ | || | _____ _____ | || | ____ ____ | | + `.::.888. :: .88888888 | | |_ _| | || | |_ _| | || ||_ \|_ _| | || ||_ _||_ _|| || | |_ _||_ _| | | + .::::::.888. :: :::`8888'.:. | | | | | || | | | | || | | \ | | | || | | | | | | || | \ \ / / | | + ::::::::::.888 ' .:::::::::::: | | | | _ | || | | | | || | | |\ \| | | || | | ' ' | | || | > `' < | | + ::::::::::::.8 ' .:8::::::::::::. | | _| |__/ | | || | _| |_ | || | _| |_\ |_ | || | \ `--' / | || | _/ /'`\ \_ | | + .::::::::::::::. .:888::::::::::::: | | |________| | || | |_____| | || ||_____|\____| | || | `.__.' | || | |____||____| | | + :::::::::::::::88:.__..:88888:::::::::::' | | | || | | || | | || | | || | | | + `'.:::::::::::88888888888.88:::::::::' | '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | + `':::_:' -- '' -'-' `':_::::'` '----------------' '----------------' '----------------' '----------------' '----------------' +"# +} diff --git a/src/fake.rs b/src/fake.rs index 6a28b05..0fe5e1a 100644 --- a/src/fake.rs +++ b/src/fake.rs @@ -1,75 +1,75 @@ -//! Currently used for WebAssembly unknown (non-web) only - -#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] -compile_error!("Unexpected pointer width for target platform"); - -use std::ffi::OsString; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - std::iter::once("en-US".to_string()) -} - -#[inline(always)] -pub(crate) fn username_os() -> Result { - Ok(username()?.into()) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - Ok(realname()?.into()) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[inline(always)] -pub(crate) fn distro_os() -> Result { - Ok(distro()?.into()) -} - -#[inline(always)] -pub(crate) fn username() -> Result { - Ok("anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok("Anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn devicename() -> Result { - Ok("Unknown".to_string()) -} - -#[inline(always)] -pub(crate) fn hostname() -> Result { - Ok("localhost".to_string()) -} - -#[inline(always)] -pub(crate) fn distro() -> Result { - Ok("Emulated".to_string()) -} - -#[inline(always)] -pub(crate) fn desktop_env() -> DesktopEnv { - DesktopEnv::Unknown("WebAssembly".to_string()) -} - -pub(crate) fn platform() -> Platform { - Platform::Unknown("Unknown".to_string()) -} - -pub(crate) fn arch() -> Arch { - if cfg!(target_pointer_width = "64") { - Arch::Wasm64 - } else { - Arch::Wasm32 - } -} +//! Currently used for WebAssembly unknown (non-web) only + +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("Unexpected pointer width for target platform"); + +use std::ffi::OsString; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + std::iter::once("en-US".to_string()) +} + +#[inline(always)] +pub(crate) fn username_os() -> Result { + Ok(username()?.into()) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + Ok(realname()?.into()) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[inline(always)] +pub(crate) fn distro_os() -> Result { + Ok(distro()?.into()) +} + +#[inline(always)] +pub(crate) fn username() -> Result { + Ok("anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok("Anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn devicename() -> Result { + Ok("Unknown".to_string()) +} + +#[inline(always)] +pub(crate) fn hostname() -> Result { + Ok("localhost".to_string()) +} + +#[inline(always)] +pub(crate) fn distro() -> Result { + Ok("Emulated".to_string()) +} + +#[inline(always)] +pub(crate) fn desktop_env() -> DesktopEnv { + DesktopEnv::Unknown("WebAssembly".to_string()) +} + +pub(crate) fn platform() -> Platform { + Platform::Unknown("Unknown".to_string()) +} + +pub(crate) fn arch() -> Arch { + if cfg!(target_pointer_width = "64") { + Arch::Wasm64 + } else { + Arch::Wasm32 + } +} diff --git a/src/fallible.rs b/src/fallible.rs index 393e442..5279c99 100644 --- a/src/fallible.rs +++ b/src/fallible.rs @@ -1,97 +1,97 @@ -//! Fallible versions of the whoami APIs. -//! -//! Some of the functions in the root module will return "Unknown" or -//! "localhost" on error. This might not be desirable in some situations. The -//! functions in this module all return a [`Result`]. - -use std::ffi::OsString; - -use crate::{platform, Result}; - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname()`] most notably in that spaces -/// are not allowed in the username. -#[inline(always)] -pub fn username() -> Result { - platform::username() -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname_os()`] most notably in that -/// spaces are not allowed in the username. -#[inline(always)] -pub fn username_os() -> Result { - platform::username_os() -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname() -> Result { - platform::realname() -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname_os() -> Result { - platform::realname_os() -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro() -> Result { - platform::distro() -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro_os() -> Result { - platform::distro_os() -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename() -> Result { - platform::devicename() -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename_os() -> Result { - platform::devicename_os() -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname() -> Result { - let mut hostname = platform::hostname()?; - - hostname.make_ascii_lowercase(); - - Ok(hostname) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname_os() -> Result { - Ok(hostname()?.into()) -} +//! Fallible versions of the whoami APIs. +//! +//! Some of the functions in the root module will return "Unknown" or +//! "localhost" on error. This might not be desirable in some situations. The +//! functions in this module all return a [`Result`]. + +use std::ffi::OsString; + +use crate::{platform, Result}; + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname()`] most notably in that spaces +/// are not allowed in the username. +#[inline(always)] +pub fn username() -> Result { + platform::username() +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname_os()`] most notably in that +/// spaces are not allowed in the username. +#[inline(always)] +pub fn username_os() -> Result { + platform::username_os() +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname() -> Result { + platform::realname() +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname_os() -> Result { + platform::realname_os() +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro() -> Result { + platform::distro() +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro_os() -> Result { + platform::distro_os() +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename() -> Result { + platform::devicename() +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename_os() -> Result { + platform::devicename_os() +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname() -> Result { + let mut hostname = platform::hostname()?; + + hostname.make_ascii_lowercase(); + + Ok(hostname) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname_os() -> Result { + Ok(hostname()?.into()) +} diff --git a/src/lib.rs b/src/lib.rs index 4ee27ca..0c3b469 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,600 +1,602 @@ -//! Crate for getting the user's username, realname and environment. -//! -//! ## Getting Started -//! Using the whoami crate is super easy! All of the public items are simple -//! functions with no parameters that return [`String`]s or [`OsString`]s (with -//! the exception of [`desktop_env()`], [`platform()`], and [`arch()`], which -//! return enums, and [`lang()`] that returns an iterator of [`String`]s). The -//! following example shows how to use all of the functions (except those that -//! return [`OsString`]): -//! -//! ```rust -//! println!( -//! "User's Name whoami::realname(): {}", -//! whoami::realname(), -//! ); -//! println!( -//! "User's Username whoami::username(): {}", -//! whoami::username(), -//! ); -//! println!( -//! "User's Language whoami::lang(): {:?}", -//! whoami::lang().collect::>(), -//! ); -//! println!( -//! "Device's Pretty Name whoami::devicename(): {}", -//! whoami::devicename(), -//! ); -//! println!( -//! "Device's Hostname whoami::hostname(): {}", -//! whoami::hostname(), -//! ); -//! println!( -//! "Device's Platform whoami::platform(): {}", -//! whoami::platform(), -//! ); -//! println!( -//! "Device's OS Distro whoami::distro(): {}", -//! whoami::distro(), -//! ); -//! println!( -//! "Device's Desktop Env. whoami::desktop_env(): {}", -//! whoami::desktop_env(), -//! ); -//! println!( -//! "Device's CPU Arch whoami::arch(): {}", -//! whoami::arch(), -//! ); -//! ``` - -#![warn( - anonymous_parameters, - missing_copy_implementations, - missing_debug_implementations, - missing_docs, - nonstandard_style, - rust_2018_idioms, - single_use_lifetimes, - trivial_casts, - trivial_numeric_casts, - unreachable_pub, - unused_extern_crates, - unused_qualifications, - variant_size_differences, - unsafe_code -)] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg", - html_favicon_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg" -)] - -const DEFAULT_USERNAME: &str = "Unknown"; -const DEFAULT_HOSTNAME: &str = "LocalHost"; - -pub mod fallible; -pub mod disp; - -#[allow(unsafe_code)] -// Unix -#[cfg_attr( - not(any(target_os = "windows", target_arch = "wasm32")), - path = "unix.rs" -)] -// Wasm32 (Daku) - FIXME: Currently routes to fake.rs -#[cfg_attr(all(target_arch = "wasm32", target_os = "daku"), path = "fake.rs")] -// Wasm32 (Wasi) - FIXME: Currently routes to fake.rs -#[cfg_attr(all(target_arch = "wasm32", target_os = "wasi"), path = "fake.rs")] -// Wasm32 (Web) -#[cfg_attr( - all( - target_arch = "wasm32", - not(target_os = "wasi"), - not(target_os = "daku"), - feature = "web", - ), - path = "web.rs" -)] -// Wasm32 (Unknown) -#[cfg_attr( - all( - target_arch = "wasm32", - not(target_os = "wasi"), - not(target_os = "daku"), - not(feature = "web"), - ), - path = "fake.rs" -)] -// Windows -#[cfg_attr( - all(target_os = "windows", not(target_arch = "wasm32")), - path = "windows.rs" -)] -mod platform; - -use std::{ - ffi::OsString, - fmt::{self, Display, Formatter}, - io::{Error, ErrorKind}, -}; - -/// This crate's convenience type alias for [`Result`](std::result::Result)s -pub type Result = std::result::Result; - -/// Region code for a [`Language`] dialect -/// -/// Uses -#[non_exhaustive] -#[repr(u32)] -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum Region { - // FIXME: V2: u32::from_ne_bytes for region codes, with `\0` for unused - // FIXME: Add aliases up to 3-4 letters, but hidden - /// Any dialect - Any, - /// `US`: United States of America - #[doc(hidden)] - Us, -} - -impl Display for Region { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Self::Any => "**", - Self::Us => "US", - }) - } -} - -/// A spoken language -/// -/// Use [`ToString::to_string()`] to convert to string of two letter lowercase -/// language code followed and underscore and uppercase region code (example: -/// `en_US`). -/// -/// Uses -#[non_exhaustive] -#[derive(Clone, Eq, PartialEq, Debug)] -// #[allow(variant_size_differences)] -pub enum Language { - #[doc(hidden)] - __(Box), - /// `en`: English - #[doc(hidden)] - En(Region), - /// `es`: Spanish - #[doc(hidden)] - Es(Region), -} - -impl Language { - /// Retrieve the region code for this language dialect. - pub fn region(&self) -> Region { - match self { - Self::__(_) => Region::Any, - Self::En(region) | Self::Es(region) => *region, - } - } -} - -impl Display for Language { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::__(code) => f.write_str(code.as_str()), - Self::En(region) => { - if *region != Region::Any { - f.write_str("en_")?; - ::fmt(region, f) - } else { - f.write_str("en") - } - } - Self::Es(region) => { - if *region != Region::Any { - f.write_str("es_")?; - ::fmt(region, f) - } else { - f.write_str("es") - } - } - } - } -} - -// FIXME: V2: Move `Unknown` variants to the top of the enum. - -/// The desktop environment of a system -#[derive(Debug, PartialEq, Eq, Clone)] -#[non_exhaustive] -pub enum DesktopEnv { - /// Popular GTK-based desktop environment on Linux - Gnome, - /// One of the desktop environments for a specific version of Windows - Windows, - /// Linux desktop environment optimized for low resource requirements - Lxde, - /// Stacking window manager for X Windows on Linux - Openbox, - /// Desktop environment for Linux, BSD and Illumos - Mate, - /// Lightweight desktop enivornment for unix-like operating systems - Xfce, - /// KDE Plasma desktop enviroment - // FIXME: Rename to 'Plasma' in whoami 2.0.0 - Kde, - /// Default desktop environment on Linux Mint - Cinnamon, - /// Tiling window manager for Linux - I3, - /// Desktop environment for MacOS - Aqua, - /// Desktop environment for iOS - Ios, - /// Desktop environment for Android - Android, - /// Running as Web Assembly on a web page - WebBrowser, - /// A desktop environment for a video game console - Console, - /// Ubuntu-branded GNOME - Ubuntu, - /// Default shell for Fuchsia - Ermine, - /// Default desktop environment for Redox - Orbital, - /// Unknown desktop environment - Unknown(String), -} - -impl Display for DesktopEnv { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::Gnome => "Gnome", - Self::Windows => "Windows", - Self::Lxde => "LXDE", - Self::Openbox => "Openbox", - Self::Mate => "Mate", - Self::Xfce => "XFCE", - Self::Kde => "KDE", - Self::Cinnamon => "Cinnamon", - Self::I3 => "I3", - Self::Aqua => "Aqua", - Self::Ios => "IOS", - Self::Android => "Android", - Self::WebBrowser => "Web Browser", - Self::Console => "Console", - Self::Ubuntu => "Ubuntu", - Self::Ermine => "Ermine", - Self::Orbital => "Orbital", - Self::Unknown(a) => a, - }) - } -} - -/// The underlying platform for a system -#[allow(missing_docs)] -#[derive(Debug, PartialEq, Eq, Clone)] -#[non_exhaustive] -pub enum Platform { - Linux, - Bsd, - Windows, - // FIXME: Non-standard casing; Rename to 'Mac' rather than 'MacOs' in - // whoami 2.0.0 - MacOS, - Illumos, - Ios, - Android, - Nintendo, - Xbox, - PlayStation, - Fuchsia, - Redox, - Unknown(String), -} - -impl Display for Platform { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::Linux => disp::display_linux(), - Self::Bsd => disp::display_bsd(), - Self::Windows => disp::display_windows(), - Self::MacOS => disp::display_macos(), - Self::Illumos => disp::display_illumos(), - Self::Ios => disp::display_ios(), - Self::Android => disp::display_android(), - Self::Nintendo => disp::display_nintendo(), - Self::Xbox => disp::display_xbox(), - Self::PlayStation => disp::display_playstation(), - Self::Fuchsia => disp::display_fuchsia(), - Self::Redox => disp::display_redox(), - Self::Unknown(a) => a, - }) - } -} - -/// The architecture of a CPU -#[non_exhaustive] -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Arch { - /// ARMv5 - ArmV5, - /// ARMv6 (Sometimes just referred to as ARM) - ArmV6, - /// ARMv7 (May or may not support Neon/Thumb) - ArmV7, - /// ARM64 (aarch64) - Arm64, - /// i386 (x86) - I386, - /// i586 (x86) - I586, - /// i686 (x86) - I686, - /// X86_64 / Amd64 - X64, - /// MIPS - Mips, - /// MIPS (LE) - MipsEl, - /// MIPS64 - Mips64, - /// MIPS64 (LE) - Mips64El, - /// PowerPC - PowerPc, - /// PowerPC64 - PowerPc64, - /// PowerPC64LE - PowerPc64Le, - /// 32-bit RISC-V - Riscv32, - /// 64-bit RISC-V - Riscv64, - /// S390x - S390x, - /// SPARC - Sparc, - /// SPARC64 - Sparc64, - /// 32-bit Web Assembly - Wasm32, - /// 64-bit Web Assembly - Wasm64, - /// Unknown Architecture - Unknown(String), -} - -impl Display for Arch { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - if let Self::Unknown(_) = self { - f.write_str("Unknown: ")?; - } - - f.write_str(match self { - Self::ArmV5 => "armv5", - Self::ArmV6 => "armv6", - Self::ArmV7 => "armv7", - Self::Arm64 => "arm64", - Self::I386 => "i386", - Self::I586 => "i586", - Self::I686 => "i686", - Self::Mips => "mips", - Self::MipsEl => "mipsel", - Self::Mips64 => "mips64", - Self::Mips64El => "mips64el", - Self::PowerPc => "powerpc", - Self::PowerPc64 => "powerpc64", - Self::PowerPc64Le => "powerpc64le", - Self::Riscv32 => "riscv32", - Self::Riscv64 => "riscv64", - Self::S390x => "s390x", - Self::Sparc => "sparc", - Self::Sparc64 => "sparc64", - Self::Wasm32 => "wasm32", - Self::Wasm64 => "wasm64", - Self::X64 => "x86_64", - Self::Unknown(arch) => arch, - }) - } -} - -/// The address width of a CPU architecture -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -#[non_exhaustive] -pub enum Width { - /// 32 bits - Bits32, - /// 64 bits - Bits64, -} - -impl Display for Width { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.write_str(match self { - Width::Bits32 => "32 bits", - Width::Bits64 => "64 bits", - }) - } -} - -impl Arch { - /// Get the width of this architecture. - pub fn width(&self) -> Result { - match self { - Arch::ArmV5 - | Arch::ArmV6 - | Arch::ArmV7 - | Arch::I386 - | Arch::I586 - | Arch::I686 - | Arch::Mips - | Arch::MipsEl - | Arch::PowerPc - | Arch::Riscv32 - | Arch::Sparc - | Arch::Wasm32 => Ok(Width::Bits32), - Arch::Arm64 - | Arch::Mips64 - | Arch::Mips64El - | Arch::PowerPc64 - | Arch::PowerPc64Le - | Arch::Riscv64 - | Arch::S390x - | Arch::Sparc64 - | Arch::Wasm64 - | Arch::X64 => Ok(Width::Bits64), - Arch::Unknown(unknown_arch) => Err(Error::new( - ErrorKind::InvalidData, - format!( - "Tried getting width of unknown arch ({})", - unknown_arch, - ), - )), - } - } -} - -/// Get the CPU Architecture. -#[inline(always)] -pub fn arch() -> Arch { - platform::arch() -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname()`] most notably in that spaces -/// are not allowed in the username. -#[inline(always)] -pub fn username() -> String { - fallible::username().unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase()) -} - -/// Get the user's username. -/// -/// On unix-systems this differs from [`realname_os()`] most notably in that -/// spaces are not allowed in the username. -#[inline(always)] -pub fn username_os() -> OsString { - fallible::username_os() - .unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase().into()) -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname() -> String { - fallible::realname() - .or_else(|_| fallible::username()) - .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned()) -} - -/// Get the user's real (full) name. -#[inline(always)] -pub fn realname_os() -> OsString { - fallible::realname_os() - .or_else(|_| fallible::username_os()) - .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into()) -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename() -> String { - fallible::devicename() - .or_else(|_| fallible::hostname()) - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string()) -} - -/// Get the device name (also known as "Pretty Name"). -/// -/// Often used to identify device for bluetooth pairing. -#[inline(always)] -pub fn devicename_os() -> OsString { - fallible::devicename_os() - .or_else(|_| fallible::hostname_os()) - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into()) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname() -> String { - fallible::hostname().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase()) -} - -/// Get the host device's hostname. -/// -/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies -/// to `devicename()` when targeting Windows. Since the hostname is -/// case-insensitive, this method normalizes to lowercase (unlike -/// [`devicename()`]). -#[inline(always)] -pub fn hostname_os() -> OsString { - fallible::hostname_os() - .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase().into()) -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro() -> String { - fallible::distro().unwrap_or_else(|_| format!("Unknown {}", platform())) -} - -/// Get the name of the operating system distribution and (possibly) version. -/// -/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" -#[inline(always)] -pub fn distro_os() -> OsString { - fallible::distro_os() - .unwrap_or_else(|_| format!("Unknown {}", platform()).into()) -} - -/// Get the desktop environment. -/// -/// Example: "gnome" or "windows" -#[inline(always)] -pub fn desktop_env() -> DesktopEnv { - platform::desktop_env() -} - -/// Get the platform. -#[inline(always)] -pub fn platform() -> Platform { - platform::platform() -} - -/// Get the user's preferred language(s). -/// -/// Returned as iterator of two letter language codes (lowercase), optionally -/// followed by a dash (-) and a two letter region code (uppercase). The most -/// preferred language is returned first, followed by next preferred, and so on. -#[inline(always)] -#[deprecated(note = "use `langs()` instead", since = "1.5.0")] -pub fn lang() -> impl Iterator { - platform::lang() -} - -/// Get the user's preferred language(s). -/// -/// Returned as iterator of [`Language`]s wrapped in [`Result`]s. The most -/// preferred language is returned first, followed by next preferred, and so on. -/// Unrecognized languages may return an error. -#[inline(always)] -pub fn langs() -> impl Iterator> { - #[allow(deprecated)] - lang().map(|string| Ok(Language::__(Box::new(string)))) -} +//! Crate for getting the user's username, realname and environment. +//! +//! ## Getting Started +//! Using the whoami crate is super easy! All of the public items are simple +//! functions with no parameters that return [`String`]s or [`OsString`]s (with +//! the exception of [`desktop_env()`], [`platform()`], and [`arch()`], which +//! return enums, and [`lang()`] that returns an iterator of [`String`]s). The +//! following example shows how to use all of the functions (except those that +//! return [`OsString`]): +//! +//! ```rust +//! println!( +//! "User's Name whoami::realname(): {}", +//! whoami::realname(), +//! ); +//! println!( +//! "User's Username whoami::username(): {}", +//! whoami::username(), +//! ); +//! println!( +//! "User's Language whoami::lang(): {:?}", +//! whoami::lang().collect::>(), +//! ); +//! println!( +//! "Device's Pretty Name whoami::devicename(): {}", +//! whoami::devicename(), +//! ); +//! println!( +//! "Device's Hostname whoami::hostname(): {}", +//! whoami::hostname(), +//! ); +//! println!( +//! "Device's Platform whoami::platform(): {}", +//! whoami::platform(), +//! ); +//! println!( +//! "Device's OS Distro whoami::distro(): {}", +//! whoami::distro(), +//! ); +//! println!( +//! "Device's Desktop Env. whoami::desktop_env(): {}", +//! whoami::desktop_env(), +//! ); +//! println!( +//! "Device's CPU Arch whoami::arch(): {}", +//! whoami::arch(), +//! ); +//! ``` + +#![warn( + anonymous_parameters, + missing_copy_implementations, + missing_debug_implementations, + missing_docs, + nonstandard_style, + rust_2018_idioms, + single_use_lifetimes, + trivial_casts, + trivial_numeric_casts, + unreachable_pub, + unused_extern_crates, + unused_qualifications, + variant_size_differences, + unsafe_code +)] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg", + html_favicon_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg" +)] + +const DEFAULT_USERNAME: &str = "Unknown"; +const DEFAULT_HOSTNAME: &str = "LocalHost"; + +pub mod fallible; +pub mod disp; + +#[allow(unsafe_code)] +// Unix +#[cfg_attr( + not(any(target_os = "windows", target_arch = "wasm32")), + path = "unix.rs" +)] +// Wasm32 (Daku) - FIXME: Currently routes to fake.rs +#[cfg_attr(all(target_arch = "wasm32", target_os = "daku"), path = "fake.rs")] +// Wasm32 (Wasi) - FIXME: Currently routes to fake.rs +#[cfg_attr(all(target_arch = "wasm32", target_os = "wasi"), path = "fake.rs")] +// Wasm32 (Web) +#[cfg_attr( + all( + target_arch = "wasm32", + not(target_os = "wasi"), + not(target_os = "daku"), + feature = "web", + ), + path = "web.rs" +)] +// Wasm32 (Unknown) +#[cfg_attr( + all( + target_arch = "wasm32", + not(target_os = "wasi"), + not(target_os = "daku"), + not(feature = "web"), + ), + path = "fake.rs" +)] +// Windows +#[cfg_attr( + all(target_os = "windows", not(target_arch = "wasm32")), + path = "windows.rs" +)] +mod platform; + +use std::{ + ffi::OsString, + fmt::{self, Display, Formatter}, + io::{Error, ErrorKind}, +}; +use is_terminal::IsTerminal; + +/// This crate's convenience type alias for [`Result`](std::result::Result)s +pub type Result = std::result::Result; + +/// Region code for a [`Language`] dialect +/// +/// Uses +#[non_exhaustive] +#[repr(u32)] +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum Region { + // FIXME: V2: u32::from_ne_bytes for region codes, with `\0` for unused + // FIXME: Add aliases up to 3-4 letters, but hidden + /// Any dialect + Any, + /// `US`: United States of America + #[doc(hidden)] + Us, +} + +impl Display for Region { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Self::Any => "**", + Self::Us => "US", + }) + } +} + +/// A spoken language +/// +/// Use [`ToString::to_string()`] to convert to string of two letter lowercase +/// language code followed and underscore and uppercase region code (example: +/// `en_US`). +/// +/// Uses +#[non_exhaustive] +#[derive(Clone, Eq, PartialEq, Debug)] +// #[allow(variant_size_differences)] +pub enum Language { + #[doc(hidden)] + __(Box), + /// `en`: English + #[doc(hidden)] + En(Region), + /// `es`: Spanish + #[doc(hidden)] + Es(Region), +} + +impl Language { + /// Retrieve the region code for this language dialect. + pub fn region(&self) -> Region { + match self { + Self::__(_) => Region::Any, + Self::En(region) | Self::Es(region) => *region, + } + } +} + +impl Display for Language { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::__(code) => f.write_str(code.as_str()), + Self::En(region) => { + if *region != Region::Any { + f.write_str("en_")?; + ::fmt(region, f) + } else { + f.write_str("en") + } + } + Self::Es(region) => { + if *region != Region::Any { + f.write_str("es_")?; + ::fmt(region, f) + } else { + f.write_str("es") + } + } + } + } +} + +// FIXME: V2: Move `Unknown` variants to the top of the enum. + +/// The desktop environment of a system +#[derive(Debug, PartialEq, Eq, Clone)] +#[non_exhaustive] +pub enum DesktopEnv { + /// Popular GTK-based desktop environment on Linux + Gnome, + /// One of the desktop environments for a specific version of Windows + Windows, + /// Linux desktop environment optimized for low resource requirements + Lxde, + /// Stacking window manager for X Windows on Linux + Openbox, + /// Desktop environment for Linux, BSD and Illumos + Mate, + /// Lightweight desktop enivornment for unix-like operating systems + Xfce, + /// KDE Plasma desktop enviroment + // FIXME: Rename to 'Plasma' in whoami 2.0.0 + Kde, + /// Default desktop environment on Linux Mint + Cinnamon, + /// Tiling window manager for Linux + I3, + /// Desktop environment for MacOS + Aqua, + /// Desktop environment for iOS + Ios, + /// Desktop environment for Android + Android, + /// Running as Web Assembly on a web page + WebBrowser, + /// A desktop environment for a video game console + Console, + /// Ubuntu-branded GNOME + Ubuntu, + /// Default shell for Fuchsia + Ermine, + /// Default desktop environment for Redox + Orbital, + /// Unknown desktop environment + Unknown(String), +} + +impl Display for DesktopEnv { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Self::Unknown(_) = self { + f.write_str("Unknown: ")?; + } + + f.write_str(match self { + Self::Gnome => "Gnome", + Self::Windows => "Windows", + Self::Lxde => "LXDE", + Self::Openbox => "Openbox", + Self::Mate => "Mate", + Self::Xfce => "XFCE", + Self::Kde => "KDE", + Self::Cinnamon => "Cinnamon", + Self::I3 => "I3", + Self::Aqua => "Aqua", + Self::Ios => "IOS", + Self::Android => "Android", + Self::WebBrowser => "Web Browser", + Self::Console => "Console", + Self::Ubuntu => "Ubuntu", + Self::Ermine => "Ermine", + Self::Orbital => "Orbital", + Self::Unknown(a) => a, + }) + } +} + +/// The underlying platform for a system +#[allow(missing_docs)] +#[derive(Debug, PartialEq, Eq, Clone)] +#[non_exhaustive] +pub enum Platform { + Linux, + Bsd, + Windows, + // FIXME: Non-standard casing; Rename to 'Mac' rather than 'MacOs' in + // whoami 2.0.0 + MacOS, + Illumos, + Ios, + Android, + Nintendo, + Xbox, + PlayStation, + Fuchsia, + Redox, + Unknown(String), +} + +impl Display for Platform { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if std::io::stdout().is_terminal() { + f.write_str(match self { + Self::Linux => disp::display_linux(), + Self::Bsd => disp::display_bsd(), + Self::Windows => disp::display_windows(), + Self::MacOS => disp::display_macos(), + Self::Illumos => disp::display_illumos(), + Self::Ios => disp::display_ios(), + Self::Android => disp::display_android(), + Self::Nintendo => disp::display_nintendo(), + Self::Xbox => disp::display_xbox(), + Self::PlayStation => disp::display_playstation(), + Self::Fuchsia => disp::display_fuchsia(), + Self::Redox => disp::display_redox(), + Self::Unknown(a) => a, + }) + } else { + write!(f, "{:?}", self) + } + } +} + + +/// The architecture of a CPU +#[non_exhaustive] +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Arch { + /// ARMv5 + ArmV5, + /// ARMv6 (Sometimes just referred to as ARM) + ArmV6, + /// ARMv7 (May or may not support Neon/Thumb) + ArmV7, + /// ARM64 (aarch64) + Arm64, + /// i386 (x86) + I386, + /// i586 (x86) + I586, + /// i686 (x86) + I686, + /// X86_64 / Amd64 + X64, + /// MIPS + Mips, + /// MIPS (LE) + MipsEl, + /// MIPS64 + Mips64, + /// MIPS64 (LE) + Mips64El, + /// PowerPC + PowerPc, + /// PowerPC64 + PowerPc64, + /// PowerPC64LE + PowerPc64Le, + /// 32-bit RISC-V + Riscv32, + /// 64-bit RISC-V + Riscv64, + /// S390x + S390x, + /// SPARC + Sparc, + /// SPARC64 + Sparc64, + /// 32-bit Web Assembly + Wasm32, + /// 64-bit Web Assembly + Wasm64, + /// Unknown Architecture + Unknown(String), +} + +impl Display for Arch { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + if let Self::Unknown(_) = self { + f.write_str("Unknown: ")?; + } + + f.write_str(match self { + Self::ArmV5 => "armv5", + Self::ArmV6 => "armv6", + Self::ArmV7 => "armv7", + Self::Arm64 => "arm64", + Self::I386 => "i386", + Self::I586 => "i586", + Self::I686 => "i686", + Self::Mips => "mips", + Self::MipsEl => "mipsel", + Self::Mips64 => "mips64", + Self::Mips64El => "mips64el", + Self::PowerPc => "powerpc", + Self::PowerPc64 => "powerpc64", + Self::PowerPc64Le => "powerpc64le", + Self::Riscv32 => "riscv32", + Self::Riscv64 => "riscv64", + Self::S390x => "s390x", + Self::Sparc => "sparc", + Self::Sparc64 => "sparc64", + Self::Wasm32 => "wasm32", + Self::Wasm64 => "wasm64", + Self::X64 => "x86_64", + Self::Unknown(arch) => arch, + }) + } +} + +/// The address width of a CPU architecture +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +#[non_exhaustive] +pub enum Width { + /// 32 bits + Bits32, + /// 64 bits + Bits64, +} + +impl Display for Width { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Width::Bits32 => "32 bits", + Width::Bits64 => "64 bits", + }) + } +} + +impl Arch { + /// Get the width of this architecture. + pub fn width(&self) -> Result { + match self { + Arch::ArmV5 + | Arch::ArmV6 + | Arch::ArmV7 + | Arch::I386 + | Arch::I586 + | Arch::I686 + | Arch::Mips + | Arch::MipsEl + | Arch::PowerPc + | Arch::Riscv32 + | Arch::Sparc + | Arch::Wasm32 => Ok(Width::Bits32), + Arch::Arm64 + | Arch::Mips64 + | Arch::Mips64El + | Arch::PowerPc64 + | Arch::PowerPc64Le + | Arch::Riscv64 + | Arch::S390x + | Arch::Sparc64 + | Arch::Wasm64 + | Arch::X64 => Ok(Width::Bits64), + Arch::Unknown(unknown_arch) => Err(Error::new( + ErrorKind::InvalidData, + format!( + "Tried getting width of unknown arch ({})", + unknown_arch, + ), + )), + } + } +} + +/// Get the CPU Architecture. +#[inline(always)] +pub fn arch() -> Arch { + platform::arch() +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname()`] most notably in that spaces +/// are not allowed in the username. +#[inline(always)] +pub fn username() -> String { + fallible::username().unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase()) +} + +/// Get the user's username. +/// +/// On unix-systems this differs from [`realname_os()`] most notably in that +/// spaces are not allowed in the username. +#[inline(always)] +pub fn username_os() -> OsString { + fallible::username_os() + .unwrap_or_else(|_| DEFAULT_USERNAME.to_lowercase().into()) +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname() -> String { + fallible::realname() + .or_else(|_| fallible::username()) + .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned()) +} + +/// Get the user's real (full) name. +#[inline(always)] +pub fn realname_os() -> OsString { + fallible::realname_os() + .or_else(|_| fallible::username_os()) + .unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into()) +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename() -> String { + fallible::devicename() + .or_else(|_| fallible::hostname()) + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string()) +} + +/// Get the device name (also known as "Pretty Name"). +/// +/// Often used to identify device for bluetooth pairing. +#[inline(always)] +pub fn devicename_os() -> OsString { + fallible::devicename_os() + .or_else(|_| fallible::hostname_os()) + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_string().into()) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname() -> String { + fallible::hostname().unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase()) +} + +/// Get the host device's hostname. +/// +/// Limited to a-z (case insensitve), 0-9, and dashes. This limit also applies +/// to `devicename()` when targeting Windows. Since the hostname is +/// case-insensitive, this method normalizes to lowercase (unlike +/// [`devicename()`]). +#[inline(always)] +pub fn hostname_os() -> OsString { + fallible::hostname_os() + .unwrap_or_else(|_| DEFAULT_HOSTNAME.to_lowercase().into()) +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro() -> String { + fallible::distro().unwrap_or_else(|_| format!("Unknown {}", platform())) +} + +/// Get the name of the operating system distribution and (possibly) version. +/// +/// Example: "Windows 10" or "Fedora 26 (Workstation Edition)" +#[inline(always)] +pub fn distro_os() -> OsString { + fallible::distro_os() + .unwrap_or_else(|_| format!("Unknown {}", platform()).into()) +} + +/// Get the desktop environment. +/// +/// Example: "gnome" or "windows" +#[inline(always)] +pub fn desktop_env() -> DesktopEnv { + platform::desktop_env() +} + +/// Get the platform. +#[inline(always)] +pub fn platform() -> Platform { + platform::platform() +} + +/// Get the user's preferred language(s). +/// +/// Returned as iterator of two letter language codes (lowercase), optionally +/// followed by a dash (-) and a two letter region code (uppercase). The most +/// preferred language is returned first, followed by next preferred, and so on. +#[inline(always)] +#[deprecated(note = "use `langs()` instead", since = "1.5.0")] +pub fn lang() -> impl Iterator { + platform::lang() +} + +/// Get the user's preferred language(s). +/// +/// Returned as iterator of [`Language`]s wrapped in [`Result`]s. The most +/// preferred language is returned first, followed by next preferred, and so on. +/// Unrecognized languages may return an error. +#[inline(always)] +pub fn langs() -> impl Iterator> { + #[allow(deprecated)] + lang().map(|string| Ok(Language::__(Box::new(string)))) +} diff --git a/src/unix.rs b/src/unix.rs index 99cdcc8..3f867c7 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -1,681 +1,681 @@ -use std::{ - borrow::Cow, - ffi::{c_void, CStr, OsString}, - io::{Error, ErrorKind}, - mem, - os::{ - raw::{c_char, c_int}, - unix::ffi::OsStringExt, - }, -}; -#[cfg(target_os = "macos")] -use std::{ - os::{ - raw::{c_long, c_uchar}, - unix::ffi::OsStrExt, - }, - ptr::null_mut, -}; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[repr(C)] -struct PassWd { - pw_name: *const c_void, - pw_passwd: *const c_void, - pw_uid: u32, - pw_gid: u32, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_change: isize, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_class: *const c_void, - pw_gecos: *const c_void, - pw_dir: *const c_void, - pw_shell: *const c_void, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_expire: isize, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_fields: i32, -} - -extern "system" { - fn getpwuid_r( - uid: u32, - pwd: *mut PassWd, - buf: *mut c_void, - buflen: usize, - result: *mut *mut PassWd, - ) -> i32; - fn geteuid() -> u32; - fn gethostname(name: *mut c_void, len: usize) -> i32; -} - -#[cfg(target_os = "macos")] -#[link(name = "CoreFoundation", kind = "framework")] -#[link(name = "SystemConfiguration", kind = "framework")] -extern "system" { - fn CFStringGetCString( - the_string: *mut c_void, - buffer: *mut u8, - buffer_size: c_long, - encoding: u32, - ) -> c_uchar; - fn CFStringGetLength(the_string: *mut c_void) -> c_long; - fn CFStringGetMaximumSizeForEncoding( - length: c_long, - encoding: u32, - ) -> c_long; - fn SCDynamicStoreCopyComputerName( - store: *mut c_void, - encoding: *mut u32, - ) -> *mut c_void; - fn CFRelease(cf: *const c_void); -} - -unsafe fn strlen(cs: *const c_void) -> usize { - let mut len = 0; - let mut cs: *const u8 = cs.cast(); - while *cs != 0 { - len += 1; - cs = cs.offset(1); - } - len -} - -unsafe fn strlen_gecos(cs: *const c_void) -> usize { - let mut len = 0; - let mut cs: *const u8 = cs.cast(); - while *cs != 0 && *cs != b',' { - len += 1; - cs = cs.offset(1); - } - len -} - -// Convert an OsString into a String -fn string_from_os(string: OsString) -> String { - match string.into_string() { - Ok(string) => string, - Err(string) => string.to_string_lossy().to_string(), - } -} - -fn os_from_cstring_gecos(string: *const c_void) -> Result { - if string.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - // Get a byte slice of the c string. - let slice = unsafe { - let length = strlen_gecos(string); - - if length == 0 { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - std::slice::from_raw_parts(string.cast(), length) - }; - - // Turn byte slice into Rust String. - Ok(OsString::from_vec(slice.to_vec())) -} - -fn os_from_cstring(string: *const c_void) -> Result { - if string.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - // Get a byte slice of the c string. - let slice = unsafe { - let length = strlen(string); - - if length == 0 { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - std::slice::from_raw_parts(string.cast(), length) - }; - - // Turn byte slice into Rust String. - Ok(OsString::from_vec(slice.to_vec())) -} - -#[cfg(target_os = "macos")] -fn os_from_cfstring(string: *mut c_void) -> OsString { - if string.is_null() { - return "".to_string().into(); - } - - unsafe { - let len = CFStringGetLength(string); - let capacity = - CFStringGetMaximumSizeForEncoding(len, 134_217_984 /* UTF8 */) + 1; - let mut out = Vec::with_capacity(capacity as usize); - if CFStringGetCString( - string, - out.as_mut_ptr(), - capacity, - 134_217_984, /* UTF8 */ - ) != 0 - { - out.set_len(strlen(out.as_ptr().cast())); // Remove trailing NUL byte - out.shrink_to_fit(); - CFRelease(string); - OsString::from_vec(out) - } else { - CFRelease(string); - "".to_string().into() - } - } -} - -// This function must allocate, because a slice or Cow would still -// reference `passwd` which is dropped when this function returns. -#[inline(always)] -fn getpwuid(real: bool) -> Result { - const BUF_SIZE: usize = 16_384; // size from the man page - let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit(); - let mut passwd = mem::MaybeUninit::::uninit(); - let mut _passwd = mem::MaybeUninit::<*mut PassWd>::uninit(); - - // Get PassWd `struct`. - let passwd = unsafe { - let ret = getpwuid_r( - geteuid(), - passwd.as_mut_ptr(), - buffer.as_mut_ptr() as *mut c_void, - BUF_SIZE, - _passwd.as_mut_ptr(), - ); - - if ret != 0 { - return Err(Error::last_os_error()); - } - - let _passwd = _passwd.assume_init(); - - if _passwd.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - passwd.assume_init() - }; - - // Extract names. - if real { - os_from_cstring_gecos(passwd.pw_gecos) - } else { - os_from_cstring(passwd.pw_name) - } -} - -pub(crate) fn username() -> Result { - Ok(string_from_os(username_os()?)) -} - -pub(crate) fn username_os() -> Result { - getpwuid(false) -} - -pub(crate) fn realname() -> Result { - Ok(string_from_os(realname_os()?)) -} - -pub(crate) fn realname_os() -> Result { - getpwuid(true) -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[cfg(not(any(target_os = "macos", target_os = "illumos")))] -pub(crate) fn devicename() -> Result { - let machine_info = std::fs::read("/etc/machine-info")?; - let machine_info = String::from_utf8_lossy(&machine_info); - - for i in machine_info.split('\n') { - let mut j = i.split('='); - - if j.next() == Some("PRETTY_HOSTNAME") { - if let Some(value) = j.next() { - // FIXME: Can " be escaped in pretty name? - return Ok(value.trim_matches('"').to_string()); - } - } - } - - Err(Error::new(ErrorKind::NotFound, "Missing record")) -} - -#[cfg(target_os = "macos")] -pub(crate) fn devicename() -> Result { - Ok(string_from_os(devicename_os()?)) -} - -#[cfg(target_os = "macos")] -pub(crate) fn devicename_os() -> Result { - let out = os_from_cfstring(unsafe { - SCDynamicStoreCopyComputerName(null_mut(), null_mut()) - }); - - if out.as_bytes().is_empty() { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - Ok(out) -} - -#[cfg(target_os = "illumos")] -pub(crate) fn devicename() -> Result { - let program = std::fs::read("/etc/nodename")?; - let mut nodename = String::from_utf8_lossy(&program).to_string(); - // Remove the trailing newline - let _ = nodename.pop(); - - if nodename.is_empty() { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - Ok(nodename) -} - -pub(crate) fn hostname() -> Result { - Ok(string_from_os(hostname_os()?)) -} - -fn hostname_os() -> Result { - // Maximum hostname length = 255, plus a NULL byte. - let mut string = Vec::::with_capacity(256); - - unsafe { - if gethostname(string.as_mut_ptr() as *mut c_void, 255) == -1 { - return Err(Error::last_os_error()); - } - - string.set_len(strlen(string.as_ptr() as *const c_void)); - }; - - Ok(OsString::from_vec(string)) -} - -#[cfg(target_os = "macos")] -fn distro_xml(data: String) -> Result { - let mut product_name = None; - let mut user_visible_version = None; - - if let Some(start) = data.find("") { - if let Some(end) = data.find("") { - let mut set_product_name = false; - let mut set_user_visible_version = false; - - for line in data[start + "".len()..end].lines() { - let line = line.trim(); - - if line.starts_with("") { - match line["".len()..].trim_end_matches("") { - "ProductName" => set_product_name = true, - "ProductUserVisibleVersion" => { - set_user_visible_version = true - } - "ProductVersion" => { - if user_visible_version.is_none() { - set_user_visible_version = true - } - } - _ => {} - } - } else if line.starts_with("") { - if set_product_name { - product_name = Some( - line["".len()..] - .trim_end_matches(""), - ); - set_product_name = false; - } else if set_user_visible_version { - user_visible_version = Some( - line["".len()..] - .trim_end_matches(""), - ); - set_user_visible_version = false; - } - } - } - } - } - - Ok(if let Some(product_name) = product_name { - if let Some(user_visible_version) = user_visible_version { - format!("{} {}", product_name, user_visible_version) - } else { - product_name.to_string() - } - } else { - user_visible_version - .map(|v| format!("Mac OS (Unknown) {}", v)) - .ok_or_else(|| { - Error::new(ErrorKind::InvalidData, "Parsing failed") - })? - }) -} - -#[cfg(target_os = "macos")] -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -#[cfg(target_os = "macos")] -pub(crate) fn distro() -> Result { - if let Ok(data) = std::fs::read_to_string( - "/System/Library/CoreServices/ServerVersion.plist", - ) { - distro_xml(data) - } else if let Ok(data) = std::fs::read_to_string( - "/System/Library/CoreServices/SystemVersion.plist", - ) { - distro_xml(data) - } else { - Err(Error::new(ErrorKind::NotFound, "Missing record")) - } -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn distro() -> Result { - let program = std::fs::read("/etc/os-release")?; - let distro = String::from_utf8_lossy(&program); - let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); - let mut fallback = None; - - for i in distro.split('\n') { - let mut j = i.split('='); - - match j.next().ok_or_else(err)? { - "PRETTY_NAME" => { - return Ok(j - .next() - .ok_or_else(err)? - .trim_matches('"') - .to_string()); - } - "NAME" => { - fallback = Some( - j.next().ok_or_else(err)?.trim_matches('"').to_string(), - ) - } - _ => {} - } - } - - fallback.ok_or_else(err) -} - -#[cfg(target_os = "macos")] -#[inline(always)] -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::Aqua -} - -#[cfg(not(target_os = "macos"))] -#[inline(always)] -pub(crate) fn desktop_env() -> DesktopEnv { - match std::env::var_os("DESKTOP_SESSION") - .map(|env| env.to_string_lossy().to_string()) - { - Some(env_orig) => { - let env = env_orig.to_uppercase(); - - if env.contains("GNOME") { - DesktopEnv::Gnome - } else if env.contains("LXDE") { - DesktopEnv::Lxde - } else if env.contains("OPENBOX") { - DesktopEnv::Openbox - } else if env.contains("I3") { - DesktopEnv::I3 - } else if env.contains("UBUNTU") { - DesktopEnv::Ubuntu - } else if env.contains("PLASMA5") { - DesktopEnv::Kde - } else { - DesktopEnv::Unknown(env_orig) - } - } - // TODO: Other Linux Desktop Environments - None => DesktopEnv::Unknown("Unknown".to_string()), - } -} - -#[cfg(target_os = "macos")] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::MacOS -} - -#[cfg(not(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd", - target_os = "illumos" -)))] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Linux -} - -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" -))] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Bsd -} - -#[cfg(target_os = "illumos")] -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Illumos -} - -struct LangIter { - array: String, - index: Option, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if self.index? && self.array.contains('-') { - self.index = Some(false); - let mut temp = self.array.split('-').next()?.to_string(); - mem::swap(&mut temp, &mut self.array); - Some(temp) - } else { - self.index = None; - let mut temp = String::new(); - mem::swap(&mut temp, &mut self.array); - Some(temp) - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - const DEFAULT_LANG: &str = "en_US"; - - let array = std::env::var("LANG") - .unwrap_or_default() - .split('.') - .next() - .unwrap_or(DEFAULT_LANG) - .to_string(); - let array = if array == "C" { - DEFAULT_LANG.to_string() - } else { - array - }; - - LangIter { - array: array.replace('_', "-"), - index: Some(true), - } -} - -#[repr(C)] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos" -))] -struct UtsName { - #[cfg(not(target_os = "dragonfly"))] - sysname: [c_char; 256], - #[cfg(target_os = "dragonfly")] - sysname: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - nodename: [c_char; 256], - #[cfg(target_os = "dragonfly")] - nodename: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - release: [c_char; 256], - #[cfg(target_os = "dragonfly")] - release: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - version: [c_char; 256], - #[cfg(target_os = "dragonfly")] - version: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - machine: [c_char; 256], - #[cfg(target_os = "dragonfly")] - machine: [c_char; 32], -} - -#[repr(C)] -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "redox" -))] -struct UtsName { - sysname: [c_char; 65], - nodename: [c_char; 65], - release: [c_char; 65], - version: [c_char; 65], - machine: [c_char; 65], - domainname: [c_char; 65], -} - -// Buffer initialization -impl Default for UtsName { - fn default() -> Self { - unsafe { mem::zeroed() } - } -} - -extern "C" { - #[cfg(not(target_os = "freebsd"))] - fn uname(buf: *mut UtsName) -> c_int; - - #[cfg(target_os = "freebsd")] - fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; -} -#[inline] -#[cfg(target_os = "freebsd")] -unsafe extern "C" fn uname(buf: *mut UtsName) -> c_int { - __xuname(256, buf.cast()) -} - -impl Arch { - fn from_str(s: Cow<'_, str>) -> Self { - let arch_str = match s { - Cow::Borrowed(str) => str, - Cow::Owned(ref str) => str, - }; - match arch_str { - "aarch64" | "arm64" | "aarch64_be" | "armv8b" | "armv8l" => { - Arch::Arm64 - } - "armv5" => Arch::ArmV5, - "armv6" | "arm" => Arch::ArmV6, - "armv7" => Arch::ArmV7, - "i386" => Arch::I386, - "i586" => Arch::I586, - "i686" | "i686-AT386" => Arch::I686, - "mips" => Arch::Mips, - "mipsel" => Arch::MipsEl, - "mips64" => Arch::Mips64, - "mips64el" => Arch::Mips64El, - "powerpc" | "ppc" | "ppcle" => Arch::PowerPc, - "powerpc64" | "ppc64" | "ppc64le" => Arch::PowerPc64, - "powerpc64le" => Arch::PowerPc64Le, - "riscv32" => Arch::Riscv32, - "riscv64" => Arch::Riscv64, - "s390x" => Arch::S390x, - "sparc" => Arch::Sparc, - "sparc64" => Arch::Sparc64, - "wasm32" => Arch::Wasm32, - "wasm64" => Arch::Wasm64, - "x86_64" | "amd64" => Arch::X64, - _ => Arch::Unknown(arch_str.to_owned()), - } - } -} - -pub(crate) fn arch() -> Arch { - let mut buf = UtsName::default(); - let result = unsafe { uname(&mut buf) }; - if result == -1 { - return Arch::Unknown("uname(2) failed to execute".to_owned()); - } - - let arch_str = - unsafe { CStr::from_ptr(buf.machine.as_ptr()) }.to_string_lossy(); - - Arch::from_str(arch_str) -} +use std::{ + borrow::Cow, + ffi::{c_void, CStr, OsString}, + io::{Error, ErrorKind}, + mem, + os::{ + raw::{c_char, c_int}, + unix::ffi::OsStringExt, + }, +}; +#[cfg(target_os = "macos")] +use std::{ + os::{ + raw::{c_long, c_uchar}, + unix::ffi::OsStrExt, + }, + ptr::null_mut, +}; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[repr(C)] +struct PassWd { + pw_name: *const c_void, + pw_passwd: *const c_void, + pw_uid: u32, + pw_gid: u32, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_change: isize, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_class: *const c_void, + pw_gecos: *const c_void, + pw_dir: *const c_void, + pw_shell: *const c_void, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_expire: isize, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_fields: i32, +} + +extern "system" { + fn getpwuid_r( + uid: u32, + pwd: *mut PassWd, + buf: *mut c_void, + buflen: usize, + result: *mut *mut PassWd, + ) -> i32; + fn geteuid() -> u32; + fn gethostname(name: *mut c_void, len: usize) -> i32; +} + +#[cfg(target_os = "macos")] +#[link(name = "CoreFoundation", kind = "framework")] +#[link(name = "SystemConfiguration", kind = "framework")] +extern "system" { + fn CFStringGetCString( + the_string: *mut c_void, + buffer: *mut u8, + buffer_size: c_long, + encoding: u32, + ) -> c_uchar; + fn CFStringGetLength(the_string: *mut c_void) -> c_long; + fn CFStringGetMaximumSizeForEncoding( + length: c_long, + encoding: u32, + ) -> c_long; + fn SCDynamicStoreCopyComputerName( + store: *mut c_void, + encoding: *mut u32, + ) -> *mut c_void; + fn CFRelease(cf: *const c_void); +} + +unsafe fn strlen(cs: *const c_void) -> usize { + let mut len = 0; + let mut cs: *const u8 = cs.cast(); + while *cs != 0 { + len += 1; + cs = cs.offset(1); + } + len +} + +unsafe fn strlen_gecos(cs: *const c_void) -> usize { + let mut len = 0; + let mut cs: *const u8 = cs.cast(); + while *cs != 0 && *cs != b',' { + len += 1; + cs = cs.offset(1); + } + len +} + +// Convert an OsString into a String +fn string_from_os(string: OsString) -> String { + match string.into_string() { + Ok(string) => string, + Err(string) => string.to_string_lossy().to_string(), + } +} + +fn os_from_cstring_gecos(string: *const c_void) -> Result { + if string.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + // Get a byte slice of the c string. + let slice = unsafe { + let length = strlen_gecos(string); + + if length == 0 { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + std::slice::from_raw_parts(string.cast(), length) + }; + + // Turn byte slice into Rust String. + Ok(OsString::from_vec(slice.to_vec())) +} + +fn os_from_cstring(string: *const c_void) -> Result { + if string.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + // Get a byte slice of the c string. + let slice = unsafe { + let length = strlen(string); + + if length == 0 { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + std::slice::from_raw_parts(string.cast(), length) + }; + + // Turn byte slice into Rust String. + Ok(OsString::from_vec(slice.to_vec())) +} + +#[cfg(target_os = "macos")] +fn os_from_cfstring(string: *mut c_void) -> OsString { + if string.is_null() { + return "".to_string().into(); + } + + unsafe { + let len = CFStringGetLength(string); + let capacity = + CFStringGetMaximumSizeForEncoding(len, 134_217_984 /* UTF8 */) + 1; + let mut out = Vec::with_capacity(capacity as usize); + if CFStringGetCString( + string, + out.as_mut_ptr(), + capacity, + 134_217_984, /* UTF8 */ + ) != 0 + { + out.set_len(strlen(out.as_ptr().cast())); // Remove trailing NUL byte + out.shrink_to_fit(); + CFRelease(string); + OsString::from_vec(out) + } else { + CFRelease(string); + "".to_string().into() + } + } +} + +// This function must allocate, because a slice or Cow would still +// reference `passwd` which is dropped when this function returns. +#[inline(always)] +fn getpwuid(real: bool) -> Result { + const BUF_SIZE: usize = 16_384; // size from the man page + let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit(); + let mut passwd = mem::MaybeUninit::::uninit(); + let mut _passwd = mem::MaybeUninit::<*mut PassWd>::uninit(); + + // Get PassWd `struct`. + let passwd = unsafe { + let ret = getpwuid_r( + geteuid(), + passwd.as_mut_ptr(), + buffer.as_mut_ptr() as *mut c_void, + BUF_SIZE, + _passwd.as_mut_ptr(), + ); + + if ret != 0 { + return Err(Error::last_os_error()); + } + + let _passwd = _passwd.assume_init(); + + if _passwd.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + passwd.assume_init() + }; + + // Extract names. + if real { + os_from_cstring_gecos(passwd.pw_gecos) + } else { + os_from_cstring(passwd.pw_name) + } +} + +pub(crate) fn username() -> Result { + Ok(string_from_os(username_os()?)) +} + +pub(crate) fn username_os() -> Result { + getpwuid(false) +} + +pub(crate) fn realname() -> Result { + Ok(string_from_os(realname_os()?)) +} + +pub(crate) fn realname_os() -> Result { + getpwuid(true) +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[cfg(not(any(target_os = "macos", target_os = "illumos")))] +pub(crate) fn devicename() -> Result { + let machine_info = std::fs::read("/etc/machine-info")?; + let machine_info = String::from_utf8_lossy(&machine_info); + + for i in machine_info.split('\n') { + let mut j = i.split('='); + + if j.next() == Some("PRETTY_HOSTNAME") { + if let Some(value) = j.next() { + // FIXME: Can " be escaped in pretty name? + return Ok(value.trim_matches('"').to_string()); + } + } + } + + Err(Error::new(ErrorKind::NotFound, "Missing record")) +} + +#[cfg(target_os = "macos")] +pub(crate) fn devicename() -> Result { + Ok(string_from_os(devicename_os()?)) +} + +#[cfg(target_os = "macos")] +pub(crate) fn devicename_os() -> Result { + let out = os_from_cfstring(unsafe { + SCDynamicStoreCopyComputerName(null_mut(), null_mut()) + }); + + if out.as_bytes().is_empty() { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + Ok(out) +} + +#[cfg(target_os = "illumos")] +pub(crate) fn devicename() -> Result { + let program = std::fs::read("/etc/nodename")?; + let mut nodename = String::from_utf8_lossy(&program).to_string(); + // Remove the trailing newline + let _ = nodename.pop(); + + if nodename.is_empty() { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + Ok(nodename) +} + +pub(crate) fn hostname() -> Result { + Ok(string_from_os(hostname_os()?)) +} + +fn hostname_os() -> Result { + // Maximum hostname length = 255, plus a NULL byte. + let mut string = Vec::::with_capacity(256); + + unsafe { + if gethostname(string.as_mut_ptr() as *mut c_void, 255) == -1 { + return Err(Error::last_os_error()); + } + + string.set_len(strlen(string.as_ptr() as *const c_void)); + }; + + Ok(OsString::from_vec(string)) +} + +#[cfg(target_os = "macos")] +fn distro_xml(data: String) -> Result { + let mut product_name = None; + let mut user_visible_version = None; + + if let Some(start) = data.find("") { + if let Some(end) = data.find("") { + let mut set_product_name = false; + let mut set_user_visible_version = false; + + for line in data[start + "".len()..end].lines() { + let line = line.trim(); + + if line.starts_with("") { + match line["".len()..].trim_end_matches("") { + "ProductName" => set_product_name = true, + "ProductUserVisibleVersion" => { + set_user_visible_version = true + } + "ProductVersion" => { + if user_visible_version.is_none() { + set_user_visible_version = true + } + } + _ => {} + } + } else if line.starts_with("") { + if set_product_name { + product_name = Some( + line["".len()..] + .trim_end_matches(""), + ); + set_product_name = false; + } else if set_user_visible_version { + user_visible_version = Some( + line["".len()..] + .trim_end_matches(""), + ); + set_user_visible_version = false; + } + } + } + } + } + + Ok(if let Some(product_name) = product_name { + if let Some(user_visible_version) = user_visible_version { + format!("{} {}", product_name, user_visible_version) + } else { + product_name.to_string() + } + } else { + user_visible_version + .map(|v| format!("Mac OS (Unknown) {}", v)) + .ok_or_else(|| { + Error::new(ErrorKind::InvalidData, "Parsing failed") + })? + }) +} + +#[cfg(target_os = "macos")] +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +#[cfg(target_os = "macos")] +pub(crate) fn distro() -> Result { + if let Ok(data) = std::fs::read_to_string( + "/System/Library/CoreServices/ServerVersion.plist", + ) { + distro_xml(data) + } else if let Ok(data) = std::fs::read_to_string( + "/System/Library/CoreServices/SystemVersion.plist", + ) { + distro_xml(data) + } else { + Err(Error::new(ErrorKind::NotFound, "Missing record")) + } +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +#[cfg(not(target_os = "macos"))] +pub(crate) fn distro() -> Result { + let program = std::fs::read("/etc/os-release")?; + let distro = String::from_utf8_lossy(&program); + let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); + let mut fallback = None; + + for i in distro.split('\n') { + let mut j = i.split('='); + + match j.next().ok_or_else(err)? { + "PRETTY_NAME" => { + return Ok(j + .next() + .ok_or_else(err)? + .trim_matches('"') + .to_string()); + } + "NAME" => { + fallback = Some( + j.next().ok_or_else(err)?.trim_matches('"').to_string(), + ) + } + _ => {} + } + } + + fallback.ok_or_else(err) +} + +#[cfg(target_os = "macos")] +#[inline(always)] +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::Aqua +} + +#[cfg(not(target_os = "macos"))] +#[inline(always)] +pub(crate) fn desktop_env() -> DesktopEnv { + match std::env::var_os("DESKTOP_SESSION") + .map(|env| env.to_string_lossy().to_string()) + { + Some(env_orig) => { + let env = env_orig.to_uppercase(); + + if env.contains("GNOME") { + DesktopEnv::Gnome + } else if env.contains("LXDE") { + DesktopEnv::Lxde + } else if env.contains("OPENBOX") { + DesktopEnv::Openbox + } else if env.contains("I3") { + DesktopEnv::I3 + } else if env.contains("UBUNTU") { + DesktopEnv::Ubuntu + } else if env.contains("PLASMA5") { + DesktopEnv::Kde + } else { + DesktopEnv::Unknown(env_orig) + } + } + // TODO: Other Linux Desktop Environments + None => DesktopEnv::Unknown("Unknown".to_string()), + } +} + +#[cfg(target_os = "macos")] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::MacOS +} + +#[cfg(not(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd", + target_os = "illumos" +)))] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Linux +} + +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" +))] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Bsd +} + +#[cfg(target_os = "illumos")] +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Illumos +} + +struct LangIter { + array: String, + index: Option, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if self.index? && self.array.contains('-') { + self.index = Some(false); + let mut temp = self.array.split('-').next()?.to_string(); + mem::swap(&mut temp, &mut self.array); + Some(temp) + } else { + self.index = None; + let mut temp = String::new(); + mem::swap(&mut temp, &mut self.array); + Some(temp) + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + const DEFAULT_LANG: &str = "en_US"; + + let array = std::env::var("LANG") + .unwrap_or_default() + .split('.') + .next() + .unwrap_or(DEFAULT_LANG) + .to_string(); + let array = if array == "C" { + DEFAULT_LANG.to_string() + } else { + array + }; + + LangIter { + array: array.replace('_', "-"), + index: Some(true), + } +} + +#[repr(C)] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd", + target_os = "illumos" +))] +struct UtsName { + #[cfg(not(target_os = "dragonfly"))] + sysname: [c_char; 256], + #[cfg(target_os = "dragonfly")] + sysname: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + nodename: [c_char; 256], + #[cfg(target_os = "dragonfly")] + nodename: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + release: [c_char; 256], + #[cfg(target_os = "dragonfly")] + release: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + version: [c_char; 256], + #[cfg(target_os = "dragonfly")] + version: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + machine: [c_char; 256], + #[cfg(target_os = "dragonfly")] + machine: [c_char; 32], +} + +#[repr(C)] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "redox" +))] +struct UtsName { + sysname: [c_char; 65], + nodename: [c_char; 65], + release: [c_char; 65], + version: [c_char; 65], + machine: [c_char; 65], + domainname: [c_char; 65], +} + +// Buffer initialization +impl Default for UtsName { + fn default() -> Self { + unsafe { mem::zeroed() } + } +} + +extern "C" { + #[cfg(not(target_os = "freebsd"))] + fn uname(buf: *mut UtsName) -> c_int; + + #[cfg(target_os = "freebsd")] + fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; +} +#[inline] +#[cfg(target_os = "freebsd")] +unsafe extern "C" fn uname(buf: *mut UtsName) -> c_int { + __xuname(256, buf.cast()) +} + +impl Arch { + fn from_str(s: Cow<'_, str>) -> Self { + let arch_str = match s { + Cow::Borrowed(str) => str, + Cow::Owned(ref str) => str, + }; + match arch_str { + "aarch64" | "arm64" | "aarch64_be" | "armv8b" | "armv8l" => { + Arch::Arm64 + } + "armv5" => Arch::ArmV5, + "armv6" | "arm" => Arch::ArmV6, + "armv7" => Arch::ArmV7, + "i386" => Arch::I386, + "i586" => Arch::I586, + "i686" | "i686-AT386" => Arch::I686, + "mips" => Arch::Mips, + "mipsel" => Arch::MipsEl, + "mips64" => Arch::Mips64, + "mips64el" => Arch::Mips64El, + "powerpc" | "ppc" | "ppcle" => Arch::PowerPc, + "powerpc64" | "ppc64" | "ppc64le" => Arch::PowerPc64, + "powerpc64le" => Arch::PowerPc64Le, + "riscv32" => Arch::Riscv32, + "riscv64" => Arch::Riscv64, + "s390x" => Arch::S390x, + "sparc" => Arch::Sparc, + "sparc64" => Arch::Sparc64, + "wasm32" => Arch::Wasm32, + "wasm64" => Arch::Wasm64, + "x86_64" | "amd64" => Arch::X64, + _ => Arch::Unknown(arch_str.to_owned()), + } + } +} + +pub(crate) fn arch() -> Arch { + let mut buf = UtsName::default(); + let result = unsafe { uname(&mut buf) }; + if result == -1 { + return Arch::Unknown("uname(2) failed to execute".to_owned()); + } + + let arch_str = + unsafe { CStr::from_ptr(buf.machine.as_ptr()) }.to_string_lossy(); + + Arch::from_str(arch_str) +} diff --git a/src/web.rs b/src/web.rs index cf1f619..04f93e8 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,247 +1,247 @@ -#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] -compile_error!("Unexpected pointer width for target platform"); - -use std::{ - ffi::OsString, - io::{Error, ErrorKind}, -}; - -use wasm_bindgen::JsValue; -use web_sys::window; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -// Get the user agent -fn user_agent() -> Option { - window()?.navigator().user_agent().ok() -} - -// Get the document domain -fn document_domain() -> Option { - window()?.document()?.location()?.hostname().ok() -} - -struct LangIter { - array: Vec, - index: usize, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if let Some(value) = self.array.get(self.index) { - self.index += 1; - if let Some(lang) = value.as_string() { - Some(lang) - } else { - self.next() - } - } else { - None - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - let array = if let Some(window) = window() { - window.navigator().languages().to_vec() - } else { - Vec::new() - }; - let index = 0; - - LangIter { array, index } -} - -#[inline(always)] -pub(crate) fn username_os() -> Result { - Ok(username()?.into()) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - Ok(realname()?.into()) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - Ok(devicename()?.into()) -} - -#[inline(always)] -pub(crate) fn distro_os() -> Result { - Ok(distro()?.into()) -} - -#[inline(always)] -pub(crate) fn username() -> Result { - Ok("anonymous".to_string()) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok("Anonymous".to_string()) -} - -pub(crate) fn devicename() -> Result { - let orig_string = user_agent().unwrap_or_default(); - - let start = if let Some(s) = orig_string.rfind(' ') { - s - } else { - return Ok("Unknown Browser".to_string()); - }; - - let string = orig_string - .get(start + 1..) - .unwrap_or("Unknown Browser") - .replace('/', " "); - - Ok(if let Some(s) = string.rfind("Safari") { - if let Some(s) = orig_string.rfind("Chrome") { - if let Some(e) = orig_string.get(s..).unwrap_or_default().find(' ') - { - orig_string - .get(s..) - .unwrap_or("Chrome") - .get(..e) - .unwrap_or("Chrome") - .replace('/', " ") - } else { - "Chrome".to_string() - } - } else if orig_string.contains("Linux") { - "GNOME Web".to_string() - } else { - string.get(s..).unwrap_or("Safari").replace('/', " ") - } - } else if string.contains("Edg ") { - string.replace("Edg ", "Edge ") - } else if string.contains("OPR ") { - string.replace("OPR ", "Opera ") - } else { - string - }) -} - -#[inline(always)] -pub(crate) fn hostname() -> Result { - document_domain() - .filter(|x| !x.is_empty()) - .ok_or_else(|| Error::new(ErrorKind::NotFound, "Domain missing")) -} - -pub(crate) fn distro() -> Result { - let string = - user_agent().ok_or_else(|| Error::from(ErrorKind::PermissionDenied))?; - let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); - let begin = string.find('(').ok_or_else(err)?; - let end = string.find(')').ok_or_else(err)?; - let string = &string[begin + 1..end]; - - Ok(if string.contains("Win32") || string.contains("Win64") { - let begin = if let Some(b) = string.find("NT") { - b - } else { - return Ok("Windows".to_string()); - }; - let end = if let Some(e) = string.find('.') { - e - } else { - return Ok("Windows".to_string()); - }; - let string = &string[begin + 3..end]; - - format!("Windows {}", string) - } else if string.contains("Linux") { - let string = if string.contains("X11") || string.contains("Wayland") { - let begin = if let Some(b) = string.find(';') { - b - } else { - return Ok("Unknown Linux".to_string()); - }; - &string[begin + 2..] - } else { - string - }; - - if string.starts_with("Linux") { - "Unknown Linux".to_string() - } else { - let end = if let Some(e) = string.find(';') { - e - } else { - return Ok("Unknown Linux".to_string()); - }; - string[..end].to_string() - } - } else if let Some(begin) = string.find("Mac OS X") { - if let Some(end) = string[begin..].find(';') { - string[begin..begin + end].to_string() - } else { - string[begin..].to_string().replace('_', ".") - } - } else { - // TODO: - // Platform::FreeBsd, - // Platform::Ios, - // Platform::Android, - // Platform::Nintendo, - // Platform::Xbox, - // Platform::PlayStation, - // Platform::Dive, - // Platform::Fuchsia, - // Platform::Redox - string.to_string() - }) -} - -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::WebBrowser -} - -pub(crate) fn platform() -> Platform { - let string = user_agent().unwrap_or_default(); - - let begin = if let Some(b) = string.find('(') { - b - } else { - return Platform::Unknown("Unknown".to_string()); - }; - let end = if let Some(e) = string.find(')') { - e - } else { - return Platform::Unknown("Unknown".to_string()); - }; - let string = &string[begin + 1..end]; - - if string.contains("Win32") || string.contains("Win64") { - Platform::Windows - } else if string.contains("Linux") { - Platform::Linux - } else if string.contains("Mac OS X") { - Platform::MacOS - } else { - // TODO: - // Platform::FreeBsd, - // Platform::Ios, - // Platform::Android, - // Platform::Nintendo, - // Platform::Xbox, - // Platform::PlayStation, - // Platform::Dive, - // Platform::Fuchsia, - // Platform::Redox, - Platform::Unknown(string.to_string()) - } -} - -pub(crate) fn arch() -> Arch { - if cfg!(target_pointer_width = "64") { - Arch::Wasm64 - } else { - Arch::Wasm32 - } -} +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("Unexpected pointer width for target platform"); + +use std::{ + ffi::OsString, + io::{Error, ErrorKind}, +}; + +use wasm_bindgen::JsValue; +use web_sys::window; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +// Get the user agent +fn user_agent() -> Option { + window()?.navigator().user_agent().ok() +} + +// Get the document domain +fn document_domain() -> Option { + window()?.document()?.location()?.hostname().ok() +} + +struct LangIter { + array: Vec, + index: usize, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if let Some(value) = self.array.get(self.index) { + self.index += 1; + if let Some(lang) = value.as_string() { + Some(lang) + } else { + self.next() + } + } else { + None + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + let array = if let Some(window) = window() { + window.navigator().languages().to_vec() + } else { + Vec::new() + }; + let index = 0; + + LangIter { array, index } +} + +#[inline(always)] +pub(crate) fn username_os() -> Result { + Ok(username()?.into()) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + Ok(realname()?.into()) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + Ok(devicename()?.into()) +} + +#[inline(always)] +pub(crate) fn distro_os() -> Result { + Ok(distro()?.into()) +} + +#[inline(always)] +pub(crate) fn username() -> Result { + Ok("anonymous".to_string()) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok("Anonymous".to_string()) +} + +pub(crate) fn devicename() -> Result { + let orig_string = user_agent().unwrap_or_default(); + + let start = if let Some(s) = orig_string.rfind(' ') { + s + } else { + return Ok("Unknown Browser".to_string()); + }; + + let string = orig_string + .get(start + 1..) + .unwrap_or("Unknown Browser") + .replace('/', " "); + + Ok(if let Some(s) = string.rfind("Safari") { + if let Some(s) = orig_string.rfind("Chrome") { + if let Some(e) = orig_string.get(s..).unwrap_or_default().find(' ') + { + orig_string + .get(s..) + .unwrap_or("Chrome") + .get(..e) + .unwrap_or("Chrome") + .replace('/', " ") + } else { + "Chrome".to_string() + } + } else if orig_string.contains("Linux") { + "GNOME Web".to_string() + } else { + string.get(s..).unwrap_or("Safari").replace('/', " ") + } + } else if string.contains("Edg ") { + string.replace("Edg ", "Edge ") + } else if string.contains("OPR ") { + string.replace("OPR ", "Opera ") + } else { + string + }) +} + +#[inline(always)] +pub(crate) fn hostname() -> Result { + document_domain() + .filter(|x| !x.is_empty()) + .ok_or_else(|| Error::new(ErrorKind::NotFound, "Domain missing")) +} + +pub(crate) fn distro() -> Result { + let string = + user_agent().ok_or_else(|| Error::from(ErrorKind::PermissionDenied))?; + let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); + let begin = string.find('(').ok_or_else(err)?; + let end = string.find(')').ok_or_else(err)?; + let string = &string[begin + 1..end]; + + Ok(if string.contains("Win32") || string.contains("Win64") { + let begin = if let Some(b) = string.find("NT") { + b + } else { + return Ok("Windows".to_string()); + }; + let end = if let Some(e) = string.find('.') { + e + } else { + return Ok("Windows".to_string()); + }; + let string = &string[begin + 3..end]; + + format!("Windows {}", string) + } else if string.contains("Linux") { + let string = if string.contains("X11") || string.contains("Wayland") { + let begin = if let Some(b) = string.find(';') { + b + } else { + return Ok("Unknown Linux".to_string()); + }; + &string[begin + 2..] + } else { + string + }; + + if string.starts_with("Linux") { + "Unknown Linux".to_string() + } else { + let end = if let Some(e) = string.find(';') { + e + } else { + return Ok("Unknown Linux".to_string()); + }; + string[..end].to_string() + } + } else if let Some(begin) = string.find("Mac OS X") { + if let Some(end) = string[begin..].find(';') { + string[begin..begin + end].to_string() + } else { + string[begin..].to_string().replace('_', ".") + } + } else { + // TODO: + // Platform::FreeBsd, + // Platform::Ios, + // Platform::Android, + // Platform::Nintendo, + // Platform::Xbox, + // Platform::PlayStation, + // Platform::Dive, + // Platform::Fuchsia, + // Platform::Redox + string.to_string() + }) +} + +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::WebBrowser +} + +pub(crate) fn platform() -> Platform { + let string = user_agent().unwrap_or_default(); + + let begin = if let Some(b) = string.find('(') { + b + } else { + return Platform::Unknown("Unknown".to_string()); + }; + let end = if let Some(e) = string.find(')') { + e + } else { + return Platform::Unknown("Unknown".to_string()); + }; + let string = &string[begin + 1..end]; + + if string.contains("Win32") || string.contains("Win64") { + Platform::Windows + } else if string.contains("Linux") { + Platform::Linux + } else if string.contains("Mac OS X") { + Platform::MacOS + } else { + // TODO: + // Platform::FreeBsd, + // Platform::Ios, + // Platform::Android, + // Platform::Nintendo, + // Platform::Xbox, + // Platform::PlayStation, + // Platform::Dive, + // Platform::Fuchsia, + // Platform::Redox, + Platform::Unknown(string.to_string()) + } +} + +pub(crate) fn arch() -> Arch { + if cfg!(target_pointer_width = "64") { + Arch::Wasm64 + } else { + Arch::Wasm32 + } +} diff --git a/src/windows.rs b/src/windows.rs index a0efb6a..cb14273 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -1,484 +1,484 @@ -use std::{ - convert::TryInto, - ffi::OsString, - io::Error, - mem::MaybeUninit, - os::{ - raw::{c_char, c_int, c_uchar, c_ulong, c_ushort, c_void}, - windows::ffi::OsStringExt, - }, - ptr, -}; - -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[repr(C)] -struct OsVersionInfoEx { - os_version_info_size: c_ulong, - major_version: c_ulong, - minor_version: c_ulong, - build_number: c_ulong, - platform_id: c_ulong, - sz_csd_version: [u16; 128], - service_pack_major: c_ushort, - service_pack_minor: c_ushort, - suite_mask: c_ushort, - product_type: c_uchar, - reserved: c_uchar, -} - -// Source: -// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#syntax -#[repr(C)] -struct SystemInfo { - processor_architecture: c_ushort, - reserved: c_ushort, - dw_page_size: c_ulong, - minimum_application_address: *mut c_void, - maximum_application_address: *mut c_void, - active_processor_mask: usize, - number_of_processors: c_ulong, - processor_type: c_ulong, - allocation_granularity: c_ulong, - processor_level: c_ushort, - processor_revision: c_ushort, -} - -#[allow(unused)] -#[repr(C)] -enum ExtendedNameFormat { - Unknown, // Nothing - FullyQualifiedDN, // Nothing - SamCompatible, // Hostname Followed By Username - Display, // Full Name - UniqueId, // Nothing - Canonical, // Nothing - UserPrincipal, // Nothing - CanonicalEx, // Nothing - ServicePrincipal, // Nothing - DnsDomain, // Nothing - GivenName, // Nothing - Surname, // Nothing -} - -#[allow(unused)] -#[repr(C)] -enum ComputerNameFormat { - NetBIOS, // Same as GetComputerNameW - DnsHostname, // Fancy Name - DnsDomain, // Nothing - DnsFullyQualified, // Fancy Name with, for example, .com - PhysicalNetBIOS, // Same as GetComputerNameW - PhysicalDnsHostname, // Same as GetComputerNameW - PhysicalDnsDomain, // Nothing - PhysicalDnsFullyQualified, // Fancy Name with, for example, .com - Max, -} - -const ERR_MORE_DATA: i32 = 0xEA; -const ERR_INSUFFICIENT_BUFFER: i32 = 0x7A; - -#[link(name = "secur32")] -extern "system" { - fn GetUserNameExW( - a: ExtendedNameFormat, - b: *mut c_char, - c: *mut c_ulong, - ) -> c_uchar; - fn GetUserNameW(a: *mut c_char, b: *mut c_ulong) -> c_int; - fn GetComputerNameExW( - a: ComputerNameFormat, - b: *mut c_char, - c: *mut c_ulong, - ) -> c_int; -} - -#[link(name = "kernel32")] -extern "system" { - fn GetUserPreferredUILanguages( - dw_flags: c_ulong, - pul_num_languages: *mut c_ulong, - pwsz_languages_buffer: *mut u16, - pcch_languages_buffer: *mut c_ulong, - ) -> c_int; - fn GetNativeSystemInfo(system_info: *mut SystemInfo); -} - -// Convert an OsString into a String -fn string_from_os(string: OsString) -> String { - match string.into_string() { - Ok(string) => string, - Err(string) => string.to_string_lossy().to_string(), - } -} - -pub(crate) fn username() -> Result { - Ok(string_from_os(username_os()?)) -} - -pub(crate) fn username_os() -> Result { - // Step 1. Retreive the entire length of the username - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetUserNameW(ptr::null_mut(), &mut size) == 0 - }; - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - size = name.capacity().try_into().unwrap_or(std::u32::MAX); - let orig_size = size; - let fail = - unsafe { GetUserNameW(name.as_mut_ptr().cast(), &mut size) == 0 }; - if fail { - return Err(Error::last_os_error()); - } - debug_assert_eq!(orig_size, size); - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - let terminator = name.pop(); // Remove Trailing Null - debug_assert_eq!(terminator, Some(0u16)); - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -#[inline(always)] -pub(crate) fn realname() -> Result { - Ok(string_from_os(realname_os()?)) -} - -#[inline(always)] -pub(crate) fn realname_os() -> Result { - // Step 1. Retrieve the entire length of the username - let mut buf_size = 0; - let fail = unsafe { - GetUserNameExW( - ExtendedNameFormat::Display, - ptr::null_mut(), - &mut buf_size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_MORE_DATA) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(buf_size.try_into().unwrap_or(std::usize::MAX)); - let mut name_len = name.capacity().try_into().unwrap_or(std::u32::MAX); - let fail = unsafe { - GetUserNameExW( - ExtendedNameFormat::Display, - name.as_mut_ptr().cast(), - &mut name_len, - ) == 0 - }; - if fail { - return Err(Error::last_os_error()); - } - - assert_eq!(buf_size, name_len + 1); - - unsafe { - name.set_len(name_len.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -#[inline(always)] -pub(crate) fn devicename() -> Result { - Ok(string_from_os(devicename_os()?)) -} - -#[inline(always)] -pub(crate) fn devicename_os() -> Result { - // Step 1. Retreive the entire length of the device name - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetComputerNameExW( - ComputerNameFormat::DnsHostname, - ptr::null_mut(), - &mut size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); - - if unsafe { - GetComputerNameExW( - ComputerNameFormat::DnsHostname, - name.as_mut_ptr().cast(), - &mut size, - ) == 0 - } { - return Err(Error::last_os_error()); - } - - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -pub(crate) fn hostname() -> Result { - Ok(string_from_os(hostname_os()?)) -} - -fn hostname_os() -> Result { - // Step 1. Retreive the entire length of the username - let mut size = 0; - let fail = unsafe { - // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER - GetComputerNameExW( - ComputerNameFormat::NetBIOS, - ptr::null_mut(), - &mut size, - ) == 0 - }; - - assert!(fail); - - if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { - return Err(Error::last_os_error()); - } - - // Step 2. Allocate memory to put the Windows (UTF-16) string. - let mut name: Vec = - Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); - let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); - - if unsafe { - GetComputerNameExW( - ComputerNameFormat::NetBIOS, - name.as_mut_ptr().cast(), - &mut size, - ) == 0 - } { - return Err(Error::last_os_error()); - } - - unsafe { - name.set_len(size.try_into().unwrap_or(std::usize::MAX)); - } - - // Step 3. Convert to Rust String - Ok(OsString::from_wide(&name)) -} - -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -pub(crate) fn distro() -> Result { - // Due to MingW Limitations, we must dynamically load ntdll.dll - extern "system" { - fn LoadLibraryExW( - filename: *const u16, - hfile: *mut c_void, - dwflags: c_ulong, - ) -> *mut c_void; - fn FreeLibrary(hmodule: *mut c_void) -> i32; - fn GetProcAddress( - hmodule: *mut c_void, - procname: *const c_char, - ) -> *mut c_void; - } - - let mut path = "ntdll.dll\0".encode_utf16().collect::>(); - let path = path.as_mut_ptr(); - - let inst = unsafe { LoadLibraryExW(path, ptr::null_mut(), 0x0000_0800) }; - - if inst.is_null() { - return Err(Error::last_os_error()); - } - - let mut path = "RtlGetVersion\0".bytes().collect::>(); - let path = path.as_mut_ptr().cast(); - let func = unsafe { GetProcAddress(inst, path) }; - - if func.is_null() { - if unsafe { FreeLibrary(inst) } == 0 { - return Err(Error::last_os_error()); - } - - return Err(Error::last_os_error()); - } - - let get_version: unsafe extern "system" fn(a: *mut OsVersionInfoEx) -> u32 = - unsafe { std::mem::transmute(func) }; - - let mut version = MaybeUninit::::zeroed(); - - let version = unsafe { - (*version.as_mut_ptr()).os_version_info_size = - std::mem::size_of::() as u32; - get_version(version.as_mut_ptr()); - - if FreeLibrary(inst) == 0 { - return Err(Error::last_os_error()); - } - - version.assume_init() - }; - - let product = match version.product_type { - 1 => "Workstation", - 2 => "Domain Controller", - 3 => "Server", - _ => "Unknown", - }; - - Ok(format!( - "Windows {}.{}.{} ({})", - version.major_version, - version.minor_version, - version.build_number, - product, - )) -} - -#[inline(always)] -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::Windows -} - -#[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Windows -} - -struct LangIter { - array: Vec, - index: usize, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if let Some(value) = self.array.get(self.index) { - self.index += 1; - - Some(value.to_string()) - } else { - None - } - } -} - -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - let mut num_languages = 0; - let mut buffer_size = 0; - let mut buffer; - - unsafe { - assert_ne!( - GetUserPreferredUILanguages( - 0x08, /* MUI_LANGUAGE_NAME */ - &mut num_languages, - ptr::null_mut(), // List of languages. - &mut buffer_size, - ), - 0 - ); - - buffer = Vec::with_capacity(buffer_size as usize); - - assert_ne!( - GetUserPreferredUILanguages( - 0x08, /* MUI_LANGUAGE_NAME */ - &mut num_languages, - buffer.as_mut_ptr(), // List of languages. - &mut buffer_size, - ), - 0 - ); - - buffer.set_len(buffer_size as usize); - } - - // We know it ends in two null characters. - buffer.pop(); - buffer.pop(); - - // - let array = String::from_utf16_lossy(&buffer) - .split('\0') - .map(|x| x.to_string()) - .collect(); - let index = 0; - - LangIter { array, index } -} - -pub(crate) fn arch() -> Arch { - fn proc(processor_type: c_ulong) -> Result { - Ok(match processor_type { - // PROCESSOR_INTEL_386 - 386 => Arch::I386, - // PROCESSOR_INTEL_486 - 486 => Arch::Unknown("I486".to_string()), - // PROCESSOR_INTEL_PENTIUM - 586 => Arch::I586, - // PROCESSOR_INTEL_IA64 - 2200 => Arch::Unknown("IA64".to_string()), - // PROCESSOR_AMD_X8664 - 8664 => Arch::X64, - v => return Err(v), - }) - } - - let buf: SystemInfo = unsafe { - let mut buf = MaybeUninit::uninit(); - GetNativeSystemInfo(buf.as_mut_ptr()); - buf.assume_init() - }; - - // Supported architectures, source: - // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#members - match buf.processor_architecture { - // PROCESSOR_ARCHITECTURE_INTEL - 0 => Arch::I686, - // PROCESSOR_ARCHITECTURE_ARM - 5 => Arch::ArmV6, - // PROCESSOR_ARCHITECTURE_IA64 - 6 => Arch::Unknown("IA64".to_string()), - // PROCESSOR_ARCHITECTURE_AMD64 - 9 => Arch::X64, - // PROCESSOR_ARCHITECTURE_ARM64 - 12 => Arch::Arm64, - // PROCESSOR_ARCHITECTURE_UNKNOWN - 0xFFFF => proc(buf.processor_type) - .unwrap_or_else(|e| Arch::Unknown(format!("Unknown ({})", e))), - invalid => proc(buf.processor_type).unwrap_or_else(|e| { - Arch::Unknown(format!("Invalid arch: {} ({})", invalid, e)) - }), - } -} +use std::{ + convert::TryInto, + ffi::OsString, + io::Error, + mem::MaybeUninit, + os::{ + raw::{c_char, c_int, c_uchar, c_ulong, c_ushort, c_void}, + windows::ffi::OsStringExt, + }, + ptr, +}; + +use crate::{Arch, DesktopEnv, Platform, Result}; + +#[repr(C)] +struct OsVersionInfoEx { + os_version_info_size: c_ulong, + major_version: c_ulong, + minor_version: c_ulong, + build_number: c_ulong, + platform_id: c_ulong, + sz_csd_version: [u16; 128], + service_pack_major: c_ushort, + service_pack_minor: c_ushort, + suite_mask: c_ushort, + product_type: c_uchar, + reserved: c_uchar, +} + +// Source: +// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#syntax +#[repr(C)] +struct SystemInfo { + processor_architecture: c_ushort, + reserved: c_ushort, + dw_page_size: c_ulong, + minimum_application_address: *mut c_void, + maximum_application_address: *mut c_void, + active_processor_mask: usize, + number_of_processors: c_ulong, + processor_type: c_ulong, + allocation_granularity: c_ulong, + processor_level: c_ushort, + processor_revision: c_ushort, +} + +#[allow(unused)] +#[repr(C)] +enum ExtendedNameFormat { + Unknown, // Nothing + FullyQualifiedDN, // Nothing + SamCompatible, // Hostname Followed By Username + Display, // Full Name + UniqueId, // Nothing + Canonical, // Nothing + UserPrincipal, // Nothing + CanonicalEx, // Nothing + ServicePrincipal, // Nothing + DnsDomain, // Nothing + GivenName, // Nothing + Surname, // Nothing +} + +#[allow(unused)] +#[repr(C)] +enum ComputerNameFormat { + NetBIOS, // Same as GetComputerNameW + DnsHostname, // Fancy Name + DnsDomain, // Nothing + DnsFullyQualified, // Fancy Name with, for example, .com + PhysicalNetBIOS, // Same as GetComputerNameW + PhysicalDnsHostname, // Same as GetComputerNameW + PhysicalDnsDomain, // Nothing + PhysicalDnsFullyQualified, // Fancy Name with, for example, .com + Max, +} + +const ERR_MORE_DATA: i32 = 0xEA; +const ERR_INSUFFICIENT_BUFFER: i32 = 0x7A; + +#[link(name = "secur32")] +extern "system" { + fn GetUserNameExW( + a: ExtendedNameFormat, + b: *mut c_char, + c: *mut c_ulong, + ) -> c_uchar; + fn GetUserNameW(a: *mut c_char, b: *mut c_ulong) -> c_int; + fn GetComputerNameExW( + a: ComputerNameFormat, + b: *mut c_char, + c: *mut c_ulong, + ) -> c_int; +} + +#[link(name = "kernel32")] +extern "system" { + fn GetUserPreferredUILanguages( + dw_flags: c_ulong, + pul_num_languages: *mut c_ulong, + pwsz_languages_buffer: *mut u16, + pcch_languages_buffer: *mut c_ulong, + ) -> c_int; + fn GetNativeSystemInfo(system_info: *mut SystemInfo); +} + +// Convert an OsString into a String +fn string_from_os(string: OsString) -> String { + match string.into_string() { + Ok(string) => string, + Err(string) => string.to_string_lossy().to_string(), + } +} + +pub(crate) fn username() -> Result { + Ok(string_from_os(username_os()?)) +} + +pub(crate) fn username_os() -> Result { + // Step 1. Retreive the entire length of the username + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetUserNameW(ptr::null_mut(), &mut size) == 0 + }; + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + size = name.capacity().try_into().unwrap_or(std::u32::MAX); + let orig_size = size; + let fail = + unsafe { GetUserNameW(name.as_mut_ptr().cast(), &mut size) == 0 }; + if fail { + return Err(Error::last_os_error()); + } + debug_assert_eq!(orig_size, size); + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + let terminator = name.pop(); // Remove Trailing Null + debug_assert_eq!(terminator, Some(0u16)); + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +#[inline(always)] +pub(crate) fn realname() -> Result { + Ok(string_from_os(realname_os()?)) +} + +#[inline(always)] +pub(crate) fn realname_os() -> Result { + // Step 1. Retrieve the entire length of the username + let mut buf_size = 0; + let fail = unsafe { + GetUserNameExW( + ExtendedNameFormat::Display, + ptr::null_mut(), + &mut buf_size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_MORE_DATA) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(buf_size.try_into().unwrap_or(std::usize::MAX)); + let mut name_len = name.capacity().try_into().unwrap_or(std::u32::MAX); + let fail = unsafe { + GetUserNameExW( + ExtendedNameFormat::Display, + name.as_mut_ptr().cast(), + &mut name_len, + ) == 0 + }; + if fail { + return Err(Error::last_os_error()); + } + + assert_eq!(buf_size, name_len + 1); + + unsafe { + name.set_len(name_len.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +#[inline(always)] +pub(crate) fn devicename() -> Result { + Ok(string_from_os(devicename_os()?)) +} + +#[inline(always)] +pub(crate) fn devicename_os() -> Result { + // Step 1. Retreive the entire length of the device name + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetComputerNameExW( + ComputerNameFormat::DnsHostname, + ptr::null_mut(), + &mut size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); + + if unsafe { + GetComputerNameExW( + ComputerNameFormat::DnsHostname, + name.as_mut_ptr().cast(), + &mut size, + ) == 0 + } { + return Err(Error::last_os_error()); + } + + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +pub(crate) fn hostname() -> Result { + Ok(string_from_os(hostname_os()?)) +} + +fn hostname_os() -> Result { + // Step 1. Retreive the entire length of the username + let mut size = 0; + let fail = unsafe { + // Ignore error, we know that it will be ERROR_INSUFFICIENT_BUFFER + GetComputerNameExW( + ComputerNameFormat::NetBIOS, + ptr::null_mut(), + &mut size, + ) == 0 + }; + + assert!(fail); + + if Error::last_os_error().raw_os_error() != Some(ERR_INSUFFICIENT_BUFFER) { + return Err(Error::last_os_error()); + } + + // Step 2. Allocate memory to put the Windows (UTF-16) string. + let mut name: Vec = + Vec::with_capacity(size.try_into().unwrap_or(std::usize::MAX)); + let mut size = name.capacity().try_into().unwrap_or(std::u32::MAX); + + if unsafe { + GetComputerNameExW( + ComputerNameFormat::NetBIOS, + name.as_mut_ptr().cast(), + &mut size, + ) == 0 + } { + return Err(Error::last_os_error()); + } + + unsafe { + name.set_len(size.try_into().unwrap_or(std::usize::MAX)); + } + + // Step 3. Convert to Rust String + Ok(OsString::from_wide(&name)) +} + +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +pub(crate) fn distro() -> Result { + // Due to MingW Limitations, we must dynamically load ntdll.dll + extern "system" { + fn LoadLibraryExW( + filename: *const u16, + hfile: *mut c_void, + dwflags: c_ulong, + ) -> *mut c_void; + fn FreeLibrary(hmodule: *mut c_void) -> i32; + fn GetProcAddress( + hmodule: *mut c_void, + procname: *const c_char, + ) -> *mut c_void; + } + + let mut path = "ntdll.dll\0".encode_utf16().collect::>(); + let path = path.as_mut_ptr(); + + let inst = unsafe { LoadLibraryExW(path, ptr::null_mut(), 0x0000_0800) }; + + if inst.is_null() { + return Err(Error::last_os_error()); + } + + let mut path = "RtlGetVersion\0".bytes().collect::>(); + let path = path.as_mut_ptr().cast(); + let func = unsafe { GetProcAddress(inst, path) }; + + if func.is_null() { + if unsafe { FreeLibrary(inst) } == 0 { + return Err(Error::last_os_error()); + } + + return Err(Error::last_os_error()); + } + + let get_version: unsafe extern "system" fn(a: *mut OsVersionInfoEx) -> u32 = + unsafe { std::mem::transmute(func) }; + + let mut version = MaybeUninit::::zeroed(); + + let version = unsafe { + (*version.as_mut_ptr()).os_version_info_size = + std::mem::size_of::() as u32; + get_version(version.as_mut_ptr()); + + if FreeLibrary(inst) == 0 { + return Err(Error::last_os_error()); + } + + version.assume_init() + }; + + let product = match version.product_type { + 1 => "Workstation", + 2 => "Domain Controller", + 3 => "Server", + _ => "Unknown", + }; + + Ok(format!( + "Windows {}.{}.{} ({})", + version.major_version, + version.minor_version, + version.build_number, + product, + )) +} + +#[inline(always)] +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::Windows +} + +#[inline(always)] +pub(crate) const fn platform() -> Platform { + Platform::Windows +} + +struct LangIter { + array: Vec, + index: usize, +} + +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if let Some(value) = self.array.get(self.index) { + self.index += 1; + + Some(value.to_string()) + } else { + None + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + let mut num_languages = 0; + let mut buffer_size = 0; + let mut buffer; + + unsafe { + assert_ne!( + GetUserPreferredUILanguages( + 0x08, /* MUI_LANGUAGE_NAME */ + &mut num_languages, + ptr::null_mut(), // List of languages. + &mut buffer_size, + ), + 0 + ); + + buffer = Vec::with_capacity(buffer_size as usize); + + assert_ne!( + GetUserPreferredUILanguages( + 0x08, /* MUI_LANGUAGE_NAME */ + &mut num_languages, + buffer.as_mut_ptr(), // List of languages. + &mut buffer_size, + ), + 0 + ); + + buffer.set_len(buffer_size as usize); + } + + // We know it ends in two null characters. + buffer.pop(); + buffer.pop(); + + // + let array = String::from_utf16_lossy(&buffer) + .split('\0') + .map(|x| x.to_string()) + .collect(); + let index = 0; + + LangIter { array, index } +} + +pub(crate) fn arch() -> Arch { + fn proc(processor_type: c_ulong) -> Result { + Ok(match processor_type { + // PROCESSOR_INTEL_386 + 386 => Arch::I386, + // PROCESSOR_INTEL_486 + 486 => Arch::Unknown("I486".to_string()), + // PROCESSOR_INTEL_PENTIUM + 586 => Arch::I586, + // PROCESSOR_INTEL_IA64 + 2200 => Arch::Unknown("IA64".to_string()), + // PROCESSOR_AMD_X8664 + 8664 => Arch::X64, + v => return Err(v), + }) + } + + let buf: SystemInfo = unsafe { + let mut buf = MaybeUninit::uninit(); + GetNativeSystemInfo(buf.as_mut_ptr()); + buf.assume_init() + }; + + // Supported architectures, source: + // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info#members + match buf.processor_architecture { + // PROCESSOR_ARCHITECTURE_INTEL + 0 => Arch::I686, + // PROCESSOR_ARCHITECTURE_ARM + 5 => Arch::ArmV6, + // PROCESSOR_ARCHITECTURE_IA64 + 6 => Arch::Unknown("IA64".to_string()), + // PROCESSOR_ARCHITECTURE_AMD64 + 9 => Arch::X64, + // PROCESSOR_ARCHITECTURE_ARM64 + 12 => Arch::Arm64, + // PROCESSOR_ARCHITECTURE_UNKNOWN + 0xFFFF => proc(buf.processor_type) + .unwrap_or_else(|e| Arch::Unknown(format!("Unknown ({})", e))), + invalid => proc(buf.processor_type).unwrap_or_else(|e| { + Arch::Unknown(format!("Invalid arch: {} ({})", invalid, e)) + }), + } +} From 4a7bcbc5278e8923f99cf9ebce117ff764094528 Mon Sep 17 00:00:00 2001 From: sebihutanu1 Date: Mon, 22 Jan 2024 19:12:02 +0200 Subject: [PATCH 4/7] final adjustments --- .vs/ProjectSettings.json | 3 --- .vs/slnx.sqlite | Bin 90112 -> 0 bytes 2 files changed, 3 deletions(-) delete mode 100644 .vs/ProjectSettings.json delete mode 100644 .vs/slnx.sqlite diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json deleted file mode 100644 index f8b4888..0000000 --- a/.vs/ProjectSettings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "CurrentProjectSetting": null -} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite deleted file mode 100644 index 86a29a7e566292584fa4ecb6d468f297f0c25788..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90112 zcmeI5dyrdKdBCNWEUg~*-nG}evR8JjjqU6z_TAO{VaJKJTCG=Jt#&PGH!;q#=y7Gs z)=Fzh>qnpsYbPO)X$A%YE&T)dBOxy5dt6XoayEoz zI-PC~{ToF8W0XIjzk2HZMsMeIV*%GToSAzK=h?x%W`Ek=XPdD;Zh5TtMYF+l z%J80^S9>x&CpW4BGcLK}bEy>WYkDpo%O>0pAG4bsJg9ZzIkXXFxzTC38!x-{Arpeo!-5j1WK^OG0^ z!Vr&5CRD1)L@J@EWMf2t>BU$kJ{`-9`hr1s+h7e>xyaO7wR-i`TE1E-SAEbNY zX0)qknO41FJ=C1jmO;MP+4_?E`hu0rxJQ=AjMJ9VezvJ+oK}t6muH+-MbDWVm~qm8 zcC)#|b5t{qw7a>(yfJ@~r#0Ov+22*x$Qj$tD+@a2fA>kAySj>2NqMD`n~-N-uCgLD zTltmMB^O>ia>-e=lA`qrdm?W!JI3AmYaH=JxmjG_GEQWHXqZ(R)`fKP)I$5pBj;%s zqTEZ?NgYGi7+E5ktXW9f+C`z!L=&xJ<-exuH9OpH{q>{759P|l>eZhtY9CZ9DG!tt z^dQ}U=ZT)tHdySAvdnrmU1jBV+g-hp!g$Dzn9Ys^FAtg4k(cN54WZUr#>=)=*V}dc zw7KXSsG-zm!yATfSLeg%az;$h7Qnu|K4CIDE})g~sf21vt zw%8`MZPK^b>BPV`dRx@dET+=kVACcBDmt+_%|Xj~G| zwn$ldrQM=yGBFifNab9`wFa57EqR$nle}&)JG@T)`aUvEvO=p>shuTrTH0@m5~JFm zI`a`XBHMkjz($kSJ>O$;96F>wO+2T05$(~0<)(0PO{k$=oBE?cWc*{YQDeC8gk$}G}g#1E2;^T`U zUnCSR7Wq&(AK?ShVu;U2OCH`=5X$~gv=k|n!+fz&4n%^1Fz+b{A!JhtRgSFWi(X%; z><^X%AsXdNQJ>dW43_w4IG9H@p`7_}(9iqI!APi3E|fjtFkdPc!@;OG%126hWOyM^ zfsCJXaNxy0(_wm^zojE$K&&OiqU*1#Fu^kQXyFI@!^suA`VMF?1@UlQV0nFe~~YT zgT+X=;NeT9AmUUGdH84u4NI|9E_p%`)N`K?Whx0Fui!)GmIOW^`0{+->qq_Y`Md>h zIEtVOg9f8+oFguTVypPDDPCWzwY(!eMjh{uH-vmkD9tq%R!jJe$2;!xjr%;lfXf>? z;td}O`Umw!-H0QLPGDB@QdHJE<{t~<`~M#9+dA&&D1jFc00KY&2mk>f00e*l5C8%| z00;m9An@BqU}ukk*K5DvGHcTtoO^TO`H-!??cVs{w|c=-yxZ#ekkZ!-z%oB>;T> zKWqMkj(dgsJMLNTL)^n$g*(BGa((R2*l)0(Wk13`&aSdc>=Zk~_A>v-JjZ;L`90=5 zlVyU;Fwk8R(ueb)AV+wa=)wn^KF&1!wc`c>;E ztsk(y)w*nrTSu%m%fDK_X8Dxm1C|FYOP1r71D4+2ANPK>_mjOJ=zXAfsrPvA{$7*$ zW%HMjY48F9KmZ5;0U)sD2@K7ebO&`7Q^~j1T3MaHl8vs+^nS~^@L=H&9L^Nd>1Cae zZ+K!C`-n3Cmw)J-p_TDBP1jE@ipr&rKjAz{D<{{^MW;@R%KKB#I+L{WqG!T)z91@3 zUw?;lnpVz4BEeEsRNm*_?>s>(1Hsni)wHNwyfW;ZqLqo#L@^Qj4sYz%(1d^C{7n#nXfe0&Jx}HTTMd~v@Ul3O($|SqMLg#IuxUI z!r5r~LV@VgUwdijIIW9&q8C^4L^u2P_c`xDx;FEvR{G-ns)Z<1*FNmLn^uMc*_`+C zFj1cT-cOvzXl0-}--^sSi8Arae{$YME7t<`g$IJ7GJf$3&ZD&Q;`zqR`FT+p+coVx zLMwyktAUk^qVjInyPQ#4SqVjE=e(k|f$t6sMUb-1{QOido)MY*E`4k$OzR$4tre4R zBDRjdG%ysRb)IJO!pRAu8~gNKLqS@%aMGVEMv0Dp=kcKctrO18RxgBz?(nB}5BX_b zbnWcr<|@%0`strJeMr|ve)+O5(ku@U<()6R!|A1!7gnbmbCn*VJoxMjP7kg0lopCJ z<$j{v`^a`Ke#z%Y%nZIw$T*rMWuRXcD>o8~$J2ey2$nv{+2&yT0dzVoN%#YmS|7 z*0IOtUWrxTz1wZl4WqJ`(PPy0%T1|x?#G42rv^q%y4_eM6ln3_h}ha%t#XBy58NSU zuU1sqhYp%_`%x|Bd=+V`0$pVAfLK*Ie?cX8>^JH5qB50Yy*AdobQaG`(WKkyHt-}M z;vK^#UBAB9)NB+*C!Kob(Y-E{&W-A5tTkJFt6r}b&*dvMtR_Wv?KA22AvOAisL9#H z*h;Cb*?pTx1OXAQjGb$(R29`;Q5DZO&eq3TbxO5&kJ#MhbM^d6g)a#!b<|TlD?|&O zqJ@a1I8%^?dxlK95oAKW$v0aK^z=HW-!3t*TkLAFGIn*PianE5G`!2C^P)m!^j+<> zhOpegPoOtjr~}xM#I8BSt`$+w>npTo&!E_1VeKp`xLR+h%MIXiy{60c#)WbfIfLkZ zqk->_>@?|)p+@J?PYEn%66lvrvbp74Vs;+?

TEXCzJU?Z*^)P04I_A<@nu*5mxv z&b>QCNF`xasFm`CdJFfhU3y?UatE|@+#AczqFUujxA!4-Ix@OQwD90tUcP$|hblrj z)q~qEz={PLLX#9Y_3%jtgZhRFw1->HyW5W36Dd;3cp{xmEYBu$vdU>gv?$fY++4P; z++!6jkjus9WAW*PTy)Ta92l7_TtUAnQj-^i|Qgd|aUE7d%VqM!iWpkWHu_t4gS9zsH zTvt}^GKj^-&Z1vdJ6o$a1X(lCgU6%Sgf-{Z3P`;0Ao7OodJ*r~C5$)s%02)5B0m40 zwT@VB?#csEqvK4H{ zZBN-=v%g^9YroF$_V?KyVr;f=GH+q-X69_;wx&IApSM46`=b57>`$^kVJ>nl=I@#3 z*$0@H*aPghn4dDwa(Ql!yN6w3euw=6=Vb>uH#f){IF@;h`2^R)E-+8B6U_VBXSV#7 z4*&oGAOHk_01yBIKmZ8*<_Po|4(jR9+pHoG<83KLAja5c6oD95JE;i7SXxpMi1D*& zMIgq^PACE~PBx_o#MoFu5r_e?Nkt$A!QzTQjC@Tf0x{ebQv_m+>$oBi16%hf0x_6% zw;~V&SjQBB7__=e5r~1Rql!QbP90GMVn8aY2*e;%L=lLQr?4Ur!%ZPYAjX)2ia-o3 z1r&i8P4X)OF@)q(1Y+38s|dtUkw+1T;h}LwAclm-6oD89;uV1y`Z;VvU%r;YJ%@G~ zg8FVDo;z8?uwIGlxUGiWdNGzWii=C}n-MG)V>WkihW&afPIC}vlVURm?1sI1IUciL zDRaBo(62{vm*E`-w_bfa?qUr4^z9q&eb^c$rg9tpsNAXU#l_XJlRda*WUq6(VMMQr zkqqJH#kk1sL4#M{84KBkn{LNH9JmHm%wrJi+i{M8J%(fYjba-+v1RIbMn4v*V;DOy zDk*NUT|&~=iG;%{6qaCBXc)|04kVxegdN)}eLdyXxz z_p^)K^6g5-jz8$B|VUoH?x{su{k#sLk zEqh4nB_gn2uvYFVHjVDiud*%sSL|=G zowOaWecL{0`;z_rwsqT+))%ZlvOZ@E+umz`$o3h#+x}hqUAFD^&)MqCko^~o8GY0L zS9XK#r}l>Je)PZnrO|mm&s|_X%skGXVLr~h%0ADmGoR<~-ZX|fB+Bx0zd!=00AHX1hxW!?Z$&T^&$KY<3YV7 zk)C=hba5=qasBq@>fG|Mz4lAd8XL5ZX%SEeYlq%(Oclk}9zB$Y`z zmZv1rxjZG24(2I|bTUs>Ej@E`4<(YGG`X7+Nza!YqeRkEC3jIG=~M4nISWii$(|W3T>4^^?C6b==@KPe_=?)JilAh@p zr$o||9AlJ7dVYhaMAB0mhZ&<2`I+>r#-ZKDpr!lqeV=hyPo3ZQx$VZ?NFY9qF-mHY zpTQU*D(T6KJGLA5>*;g+zJnyQ{FKE3*0@*SKFeqKQ)P#5w;22N_&nb^ywm8`Yfki? zF3z}5ubk;S_YoVFQ+?-cM4+7OJNJ@m)F=CvJ){-mX6m(3Valfv8q>m5%cNj+$fq3dq>eC$iGse9- z<=lU#@em4kXr3l;7`<57aq>^*gX-v?GY+Gi?dJuy5gXKp|0D}_`cHZ;AOD+C&++*` ze*RzAw-qiM&_^Hu1b_e#00KY&2mk>f00e*l5C8&OmjFKhhx`AnJO0pfAOHk_01yBI zKmZ5;0U!VbfB+EK8U*0{e`}00^b!aF0U!VbfB+Bx0zd!=00AHX1hzH-IRD?;;}5+D z0zd!=00AHX1b_e#00KY&2mpbtK>*JGx5hX_FM$9M00KY&2mk>f00e*l5C8%|U~3bA z^Z%_q{?L0M00e*l5C8%|00;m9AOHk_01((31mOOEYm77W5(oeRAOHk_01yBIKmZ5; z0U!Vbwl)Fy{{Pkf00e*l5C8%|00?Xi0{H&lYBuP&5c_?$X@A<@ zXPdD;Zh5TtMYF+l%J80^S9>x&C$|O*=;g16fbki}y}W+?RHarDu4J#S6zbJUpitS?X!3B{wk%XIyf{=Ta%$*YsRGmQA=HK4v#NcwYZ5zLhUj z1#Q>0pBc%RTx=qh=+bk>Ix2GMfS4>TA-=i9iA2UVpGnTfGN)ZLiPNswLT)aZM%B(H z(m7-m`nQlu9hPdDZ`3bUN%a*?UEYW3==wS2Ww zt_Y=W6{yEUE;oa`MByd(Sk}ghMWNZO6e?BR#Wq%LHjNK<)5Te)&1hH8GOc>UdZ;<4ErWcov-KtS^#v=LagQvK8K*6!{cKauIISABFV8rw zik>q!Fyo{F?Pha_=cr~JX?Jsnd1L+}PiwkUvcIdWku$cPR~B^4|L&7KcXbu5lJZI= zHzCiwTxCUQw(={hOD?>47BQMYA8$zwM zjF)Y#uD9#>X>-vvP(!KBhBpk|uFi+i<&2o1Er5M_eZpjRTtF+|Rb}O)W}(z{XGv=P zqq3W&{zzLOZLv*i+oW%=(}{s?^tPy@Sxlw7!KO_NR!VMSTsQFU>(fSYk&Y{iG(}5m z=Qi~O(Wn64YZ)}B6HZhwe*F>^&8<@&B zTXTh`(6}U^ZIQC_O1nkZWMV3|kjlA=YYj4ETk<^(M7H~4fsH1ud%nlyICMyVns`q0BHE(~%T3|pnovW#HuXn?%5OBv z(He68!>FWt{e<4^a60wZ1X8DDoAjqgRmT}gO1YdQxn-WVn6Iv(anyLHc#$Oc|GLL@ zT-yG)?cZ&4yyEKmkE`+b6XT%8LEd3?6n?t+k2K{hJ%zwW>{x)|6UuKjP%f4!>Xj7!@s1lkUQ_Z=>nn zX3}-ex3!%U_Xh4_<@kv_ZMw~`?(<$QvH3*%UxzHUJb%3_k4IY@FR)Obf~38duXxYof;f|z~RSDMLOQ# z7EC_Z*m{Q_@cjQR4{|_*KmZ5;0U!VbfB+Bx0zd!=00AHX1a3J2xc|T9$e}?X00e*l z5C8%|00;m9AOHk_01yBIx10d{{@*P}4h;eUAOHk_01yBIKmZ5;0U!VbfB+D<f00e*l5C8%|00`W20{;VF=mUcQ From 7df0490d7638d806d8e449f2acc0aedea033501a Mon Sep 17 00:00:00 2001 From: sebihutanu1 Date: Tue, 23 Jan 2024 14:19:42 +0200 Subject: [PATCH 5/7] fixed cargo fmt --- src/disp.rs | 6 +- src/fake.rs | 670 +++++++++++++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 4 +- 3 files changed, 643 insertions(+), 37 deletions(-) diff --git a/src/disp.rs b/src/disp.rs index ce7bfca..466ce89 100644 --- a/src/disp.rs +++ b/src/disp.rs @@ -44,7 +44,7 @@ pub fn display_bsd() -> &'static str { "# } -pub fn display_macos() -> &'static str{ +pub fn display_macos() -> &'static str { r#" ,xNMM. .OMMMMo @@ -94,7 +94,7 @@ pub fn display_illumos() -> &'static str { } pub fn display_ios() -> &'static str { - r#" + r#" ,xNMM. .OMMMMo lMM" @@ -217,7 +217,7 @@ pub fn display_fuchsia() -> &'static str { } pub fn display_linux() -> &'static str { - r#" + r#" .88888888:. 88888888.88888. .8888888888888888. diff --git a/src/fake.rs b/src/fake.rs index 0fe5e1a..3f867c7 100644 --- a/src/fake.rs +++ b/src/fake.rs @@ -1,75 +1,681 @@ -//! Currently used for WebAssembly unknown (non-web) only +use std::{ + borrow::Cow, + ffi::{c_void, CStr, OsString}, + io::{Error, ErrorKind}, + mem, + os::{ + raw::{c_char, c_int}, + unix::ffi::OsStringExt, + }, +}; +#[cfg(target_os = "macos")] +use std::{ + os::{ + raw::{c_long, c_uchar}, + unix::ffi::OsStrExt, + }, + ptr::null_mut, +}; -#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] -compile_error!("Unexpected pointer width for target platform"); +use crate::{Arch, DesktopEnv, Platform, Result}; -use std::ffi::OsString; +#[repr(C)] +struct PassWd { + pw_name: *const c_void, + pw_passwd: *const c_void, + pw_uid: u32, + pw_gid: u32, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_change: isize, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_class: *const c_void, + pw_gecos: *const c_void, + pw_dir: *const c_void, + pw_shell: *const c_void, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_expire: isize, + #[cfg(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" + ))] + pw_fields: i32, +} -use crate::{Arch, DesktopEnv, Platform, Result}; +extern "system" { + fn getpwuid_r( + uid: u32, + pwd: *mut PassWd, + buf: *mut c_void, + buflen: usize, + result: *mut *mut PassWd, + ) -> i32; + fn geteuid() -> u32; + fn gethostname(name: *mut c_void, len: usize) -> i32; +} -#[inline(always)] -pub(crate) fn lang() -> impl Iterator { - std::iter::once("en-US".to_string()) +#[cfg(target_os = "macos")] +#[link(name = "CoreFoundation", kind = "framework")] +#[link(name = "SystemConfiguration", kind = "framework")] +extern "system" { + fn CFStringGetCString( + the_string: *mut c_void, + buffer: *mut u8, + buffer_size: c_long, + encoding: u32, + ) -> c_uchar; + fn CFStringGetLength(the_string: *mut c_void) -> c_long; + fn CFStringGetMaximumSizeForEncoding( + length: c_long, + encoding: u32, + ) -> c_long; + fn SCDynamicStoreCopyComputerName( + store: *mut c_void, + encoding: *mut u32, + ) -> *mut c_void; + fn CFRelease(cf: *const c_void); +} + +unsafe fn strlen(cs: *const c_void) -> usize { + let mut len = 0; + let mut cs: *const u8 = cs.cast(); + while *cs != 0 { + len += 1; + cs = cs.offset(1); + } + len +} + +unsafe fn strlen_gecos(cs: *const c_void) -> usize { + let mut len = 0; + let mut cs: *const u8 = cs.cast(); + while *cs != 0 && *cs != b',' { + len += 1; + cs = cs.offset(1); + } + len +} + +// Convert an OsString into a String +fn string_from_os(string: OsString) -> String { + match string.into_string() { + Ok(string) => string, + Err(string) => string.to_string_lossy().to_string(), + } +} + +fn os_from_cstring_gecos(string: *const c_void) -> Result { + if string.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + // Get a byte slice of the c string. + let slice = unsafe { + let length = strlen_gecos(string); + + if length == 0 { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + std::slice::from_raw_parts(string.cast(), length) + }; + + // Turn byte slice into Rust String. + Ok(OsString::from_vec(slice.to_vec())) +} + +fn os_from_cstring(string: *const c_void) -> Result { + if string.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + // Get a byte slice of the c string. + let slice = unsafe { + let length = strlen(string); + + if length == 0 { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + std::slice::from_raw_parts(string.cast(), length) + }; + + // Turn byte slice into Rust String. + Ok(OsString::from_vec(slice.to_vec())) } +#[cfg(target_os = "macos")] +fn os_from_cfstring(string: *mut c_void) -> OsString { + if string.is_null() { + return "".to_string().into(); + } + + unsafe { + let len = CFStringGetLength(string); + let capacity = + CFStringGetMaximumSizeForEncoding(len, 134_217_984 /* UTF8 */) + 1; + let mut out = Vec::with_capacity(capacity as usize); + if CFStringGetCString( + string, + out.as_mut_ptr(), + capacity, + 134_217_984, /* UTF8 */ + ) != 0 + { + out.set_len(strlen(out.as_ptr().cast())); // Remove trailing NUL byte + out.shrink_to_fit(); + CFRelease(string); + OsString::from_vec(out) + } else { + CFRelease(string); + "".to_string().into() + } + } +} + +// This function must allocate, because a slice or Cow would still +// reference `passwd` which is dropped when this function returns. #[inline(always)] +fn getpwuid(real: bool) -> Result { + const BUF_SIZE: usize = 16_384; // size from the man page + let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit(); + let mut passwd = mem::MaybeUninit::::uninit(); + let mut _passwd = mem::MaybeUninit::<*mut PassWd>::uninit(); + + // Get PassWd `struct`. + let passwd = unsafe { + let ret = getpwuid_r( + geteuid(), + passwd.as_mut_ptr(), + buffer.as_mut_ptr() as *mut c_void, + BUF_SIZE, + _passwd.as_mut_ptr(), + ); + + if ret != 0 { + return Err(Error::last_os_error()); + } + + let _passwd = _passwd.assume_init(); + + if _passwd.is_null() { + return Err(Error::new(ErrorKind::NotFound, "Null record")); + } + + passwd.assume_init() + }; + + // Extract names. + if real { + os_from_cstring_gecos(passwd.pw_gecos) + } else { + os_from_cstring(passwd.pw_name) + } +} + +pub(crate) fn username() -> Result { + Ok(string_from_os(username_os()?)) +} + pub(crate) fn username_os() -> Result { - Ok(username()?.into()) + getpwuid(false) +} + +pub(crate) fn realname() -> Result { + Ok(string_from_os(realname_os()?)) } -#[inline(always)] pub(crate) fn realname_os() -> Result { - Ok(realname()?.into()) + getpwuid(true) } -#[inline(always)] +#[cfg(not(target_os = "macos"))] pub(crate) fn devicename_os() -> Result { Ok(devicename()?.into()) } -#[inline(always)] +#[cfg(not(any(target_os = "macos", target_os = "illumos")))] +pub(crate) fn devicename() -> Result { + let machine_info = std::fs::read("/etc/machine-info")?; + let machine_info = String::from_utf8_lossy(&machine_info); + + for i in machine_info.split('\n') { + let mut j = i.split('='); + + if j.next() == Some("PRETTY_HOSTNAME") { + if let Some(value) = j.next() { + // FIXME: Can " be escaped in pretty name? + return Ok(value.trim_matches('"').to_string()); + } + } + } + + Err(Error::new(ErrorKind::NotFound, "Missing record")) +} + +#[cfg(target_os = "macos")] +pub(crate) fn devicename() -> Result { + Ok(string_from_os(devicename_os()?)) +} + +#[cfg(target_os = "macos")] +pub(crate) fn devicename_os() -> Result { + let out = os_from_cfstring(unsafe { + SCDynamicStoreCopyComputerName(null_mut(), null_mut()) + }); + + if out.as_bytes().is_empty() { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + Ok(out) +} + +#[cfg(target_os = "illumos")] +pub(crate) fn devicename() -> Result { + let program = std::fs::read("/etc/nodename")?; + let mut nodename = String::from_utf8_lossy(&program).to_string(); + // Remove the trailing newline + let _ = nodename.pop(); + + if nodename.is_empty() { + return Err(Error::new(ErrorKind::InvalidData, "Empty record")); + } + + Ok(nodename) +} + +pub(crate) fn hostname() -> Result { + Ok(string_from_os(hostname_os()?)) +} + +fn hostname_os() -> Result { + // Maximum hostname length = 255, plus a NULL byte. + let mut string = Vec::::with_capacity(256); + + unsafe { + if gethostname(string.as_mut_ptr() as *mut c_void, 255) == -1 { + return Err(Error::last_os_error()); + } + + string.set_len(strlen(string.as_ptr() as *const c_void)); + }; + + Ok(OsString::from_vec(string)) +} + +#[cfg(target_os = "macos")] +fn distro_xml(data: String) -> Result { + let mut product_name = None; + let mut user_visible_version = None; + + if let Some(start) = data.find("") { + if let Some(end) = data.find("") { + let mut set_product_name = false; + let mut set_user_visible_version = false; + + for line in data[start + "".len()..end].lines() { + let line = line.trim(); + + if line.starts_with("") { + match line["".len()..].trim_end_matches("") { + "ProductName" => set_product_name = true, + "ProductUserVisibleVersion" => { + set_user_visible_version = true + } + "ProductVersion" => { + if user_visible_version.is_none() { + set_user_visible_version = true + } + } + _ => {} + } + } else if line.starts_with("") { + if set_product_name { + product_name = Some( + line["".len()..] + .trim_end_matches(""), + ); + set_product_name = false; + } else if set_user_visible_version { + user_visible_version = Some( + line["".len()..] + .trim_end_matches(""), + ); + set_user_visible_version = false; + } + } + } + } + } + + Ok(if let Some(product_name) = product_name { + if let Some(user_visible_version) = user_visible_version { + format!("{} {}", product_name, user_visible_version) + } else { + product_name.to_string() + } + } else { + user_visible_version + .map(|v| format!("Mac OS (Unknown) {}", v)) + .ok_or_else(|| { + Error::new(ErrorKind::InvalidData, "Parsing failed") + })? + }) +} + +#[cfg(target_os = "macos")] +pub(crate) fn distro_os() -> Result { + distro().map(|a| a.into()) +} + +#[cfg(target_os = "macos")] +pub(crate) fn distro() -> Result { + if let Ok(data) = std::fs::read_to_string( + "/System/Library/CoreServices/ServerVersion.plist", + ) { + distro_xml(data) + } else if let Ok(data) = std::fs::read_to_string( + "/System/Library/CoreServices/SystemVersion.plist", + ) { + distro_xml(data) + } else { + Err(Error::new(ErrorKind::NotFound, "Missing record")) + } +} + +#[cfg(not(target_os = "macos"))] pub(crate) fn distro_os() -> Result { - Ok(distro()?.into()) + distro().map(|a| a.into()) } +#[cfg(not(target_os = "macos"))] +pub(crate) fn distro() -> Result { + let program = std::fs::read("/etc/os-release")?; + let distro = String::from_utf8_lossy(&program); + let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); + let mut fallback = None; + + for i in distro.split('\n') { + let mut j = i.split('='); + + match j.next().ok_or_else(err)? { + "PRETTY_NAME" => { + return Ok(j + .next() + .ok_or_else(err)? + .trim_matches('"') + .to_string()); + } + "NAME" => { + fallback = Some( + j.next().ok_or_else(err)?.trim_matches('"').to_string(), + ) + } + _ => {} + } + } + + fallback.ok_or_else(err) +} + +#[cfg(target_os = "macos")] #[inline(always)] -pub(crate) fn username() -> Result { - Ok("anonymous".to_string()) +pub(crate) const fn desktop_env() -> DesktopEnv { + DesktopEnv::Aqua } +#[cfg(not(target_os = "macos"))] #[inline(always)] -pub(crate) fn realname() -> Result { - Ok("Anonymous".to_string()) +pub(crate) fn desktop_env() -> DesktopEnv { + match std::env::var_os("DESKTOP_SESSION") + .map(|env| env.to_string_lossy().to_string()) + { + Some(env_orig) => { + let env = env_orig.to_uppercase(); + + if env.contains("GNOME") { + DesktopEnv::Gnome + } else if env.contains("LXDE") { + DesktopEnv::Lxde + } else if env.contains("OPENBOX") { + DesktopEnv::Openbox + } else if env.contains("I3") { + DesktopEnv::I3 + } else if env.contains("UBUNTU") { + DesktopEnv::Ubuntu + } else if env.contains("PLASMA5") { + DesktopEnv::Kde + } else { + DesktopEnv::Unknown(env_orig) + } + } + // TODO: Other Linux Desktop Environments + None => DesktopEnv::Unknown("Unknown".to_string()), + } } +#[cfg(target_os = "macos")] #[inline(always)] -pub(crate) fn devicename() -> Result { - Ok("Unknown".to_string()) +pub(crate) const fn platform() -> Platform { + Platform::MacOS } +#[cfg(not(any( + target_os = "macos", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd", + target_os = "illumos" +)))] #[inline(always)] -pub(crate) fn hostname() -> Result { - Ok("localhost".to_string()) +pub(crate) const fn platform() -> Platform { + Platform::Linux } +#[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "openbsd", + target_os = "netbsd" +))] #[inline(always)] -pub(crate) fn distro() -> Result { - Ok("Emulated".to_string()) +pub(crate) const fn platform() -> Platform { + Platform::Bsd } +#[cfg(target_os = "illumos")] #[inline(always)] -pub(crate) fn desktop_env() -> DesktopEnv { - DesktopEnv::Unknown("WebAssembly".to_string()) +pub(crate) const fn platform() -> Platform { + Platform::Illumos } -pub(crate) fn platform() -> Platform { - Platform::Unknown("Unknown".to_string()) +struct LangIter { + array: String, + index: Option, } -pub(crate) fn arch() -> Arch { - if cfg!(target_pointer_width = "64") { - Arch::Wasm64 +impl Iterator for LangIter { + type Item = String; + + fn next(&mut self) -> Option { + if self.index? && self.array.contains('-') { + self.index = Some(false); + let mut temp = self.array.split('-').next()?.to_string(); + mem::swap(&mut temp, &mut self.array); + Some(temp) + } else { + self.index = None; + let mut temp = String::new(); + mem::swap(&mut temp, &mut self.array); + Some(temp) + } + } +} + +#[inline(always)] +pub(crate) fn lang() -> impl Iterator { + const DEFAULT_LANG: &str = "en_US"; + + let array = std::env::var("LANG") + .unwrap_or_default() + .split('.') + .next() + .unwrap_or(DEFAULT_LANG) + .to_string(); + let array = if array == "C" { + DEFAULT_LANG.to_string() } else { - Arch::Wasm32 + array + }; + + LangIter { + array: array.replace('_', "-"), + index: Some(true), + } +} + +#[repr(C)] +#[cfg(any( + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "netbsd", + target_os = "openbsd", + target_os = "illumos" +))] +struct UtsName { + #[cfg(not(target_os = "dragonfly"))] + sysname: [c_char; 256], + #[cfg(target_os = "dragonfly")] + sysname: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + nodename: [c_char; 256], + #[cfg(target_os = "dragonfly")] + nodename: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + release: [c_char; 256], + #[cfg(target_os = "dragonfly")] + release: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + version: [c_char; 256], + #[cfg(target_os = "dragonfly")] + version: [c_char; 32], + #[cfg(not(target_os = "dragonfly"))] + machine: [c_char; 256], + #[cfg(target_os = "dragonfly")] + machine: [c_char; 32], +} + +#[repr(C)] +#[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "fuchsia", + target_os = "redox" +))] +struct UtsName { + sysname: [c_char; 65], + nodename: [c_char; 65], + release: [c_char; 65], + version: [c_char; 65], + machine: [c_char; 65], + domainname: [c_char; 65], +} + +// Buffer initialization +impl Default for UtsName { + fn default() -> Self { + unsafe { mem::zeroed() } + } +} + +extern "C" { + #[cfg(not(target_os = "freebsd"))] + fn uname(buf: *mut UtsName) -> c_int; + + #[cfg(target_os = "freebsd")] + fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; +} +#[inline] +#[cfg(target_os = "freebsd")] +unsafe extern "C" fn uname(buf: *mut UtsName) -> c_int { + __xuname(256, buf.cast()) +} + +impl Arch { + fn from_str(s: Cow<'_, str>) -> Self { + let arch_str = match s { + Cow::Borrowed(str) => str, + Cow::Owned(ref str) => str, + }; + match arch_str { + "aarch64" | "arm64" | "aarch64_be" | "armv8b" | "armv8l" => { + Arch::Arm64 + } + "armv5" => Arch::ArmV5, + "armv6" | "arm" => Arch::ArmV6, + "armv7" => Arch::ArmV7, + "i386" => Arch::I386, + "i586" => Arch::I586, + "i686" | "i686-AT386" => Arch::I686, + "mips" => Arch::Mips, + "mipsel" => Arch::MipsEl, + "mips64" => Arch::Mips64, + "mips64el" => Arch::Mips64El, + "powerpc" | "ppc" | "ppcle" => Arch::PowerPc, + "powerpc64" | "ppc64" | "ppc64le" => Arch::PowerPc64, + "powerpc64le" => Arch::PowerPc64Le, + "riscv32" => Arch::Riscv32, + "riscv64" => Arch::Riscv64, + "s390x" => Arch::S390x, + "sparc" => Arch::Sparc, + "sparc64" => Arch::Sparc64, + "wasm32" => Arch::Wasm32, + "wasm64" => Arch::Wasm64, + "x86_64" | "amd64" => Arch::X64, + _ => Arch::Unknown(arch_str.to_owned()), + } } } + +pub(crate) fn arch() -> Arch { + let mut buf = UtsName::default(); + let result = unsafe { uname(&mut buf) }; + if result == -1 { + return Arch::Unknown("uname(2) failed to execute".to_owned()); + } + + let arch_str = + unsafe { CStr::from_ptr(buf.machine.as_ptr()) }.to_string_lossy(); + + Arch::from_str(arch_str) +} diff --git a/src/lib.rs b/src/lib.rs index 0c3b469..8f5139d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,8 +71,8 @@ const DEFAULT_USERNAME: &str = "Unknown"; const DEFAULT_HOSTNAME: &str = "LocalHost"; -pub mod fallible; pub mod disp; +pub mod fallible; #[allow(unsafe_code)] // Unix @@ -116,6 +116,7 @@ use std::{ fmt::{self, Display, Formatter}, io::{Error, ErrorKind}, }; + use is_terminal::IsTerminal; /// This crate's convenience type alias for [`Result`](std::result::Result)s @@ -321,7 +322,6 @@ impl Display for Platform { } } - /// The architecture of a CPU #[non_exhaustive] #[derive(Debug, PartialEq, Eq, Clone)] From fc605e950c56cafb2b4f26e74f6126d11e381175 Mon Sep 17 00:00:00 2001 From: sebihutanu1 Date: Tue, 23 Jan 2024 19:13:34 +0200 Subject: [PATCH 6/7] Fix Clippy errors and replace incorrect fake.rs with the correct version --- src/disp.rs | 25 ++ src/fake.rs | 670 +++------------------------------------------------- 2 files changed, 57 insertions(+), 638 deletions(-) diff --git a/src/disp.rs b/src/disp.rs index 466ce89..a07538c 100644 --- a/src/disp.rs +++ b/src/disp.rs @@ -1,3 +1,5 @@ +/// Returns a reference to a static string containing the ASCII art +/// representation of the Windows logo. pub fn display_windows() -> &'static str { r#" .oodMMMM @@ -20,6 +22,8 @@ pub fn display_windows() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the BSD logo. pub fn display_bsd() -> &'static str { r#" , , @@ -44,6 +48,8 @@ pub fn display_bsd() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the MacOS logo. pub fn display_macos() -> &'static str { r#" ,xNMM. @@ -65,6 +71,8 @@ pub fn display_macos() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the Illumos logo. pub fn display_illumos() -> &'static str { r#" ' Tw @@ -93,6 +101,8 @@ pub fn display_illumos() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the iOS logo. pub fn display_ios() -> &'static str { r#" ,xNMM. @@ -114,6 +124,8 @@ pub fn display_ios() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the Android logo. pub fn display_android() -> &'static str { r#" -o o- @@ -137,6 +149,8 @@ pub fn display_android() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the Nintendo logo. pub fn display_nintendo() -> &'static str { r#" .-----------------. .----------------. .-----------------. .----------------. .----------------. .-----------------. .----------------. .----------------. @@ -153,6 +167,9 @@ pub fn display_nintendo() -> &'static str { ⠀⠀⠀⠉⠛⠿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠛⠉ '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' "# } + +/// Returns a reference to a static string containing the ASCII art +/// representation of the Xbox logo. pub fn display_xbox() -> &'static str { r#" ⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⣤⣶⣶⣶⣶⣤⣤⣄⡀⠀⠀⠀⠀⠀⠀⠀ @@ -171,6 +188,8 @@ pub fn display_xbox() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the Playstation logo. pub fn display_playstation() -> &'static str { r#" ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣷⣶⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ @@ -188,6 +207,8 @@ pub fn display_playstation() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the Redox logo. pub fn display_redox() -> &'static str { r#" ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄ ▄ ▄ @@ -204,6 +225,8 @@ pub fn display_redox() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the Fuchsia logo. pub fn display_fuchsia() -> &'static str { r#" ▄████ ▄█▄ ▄ █ ▄▄▄▄▄ ▄█ ██ @@ -216,6 +239,8 @@ pub fn display_fuchsia() -> &'static str { "# } +/// Returns a reference to a static string containing the ASCII art +/// representation of the Linux logo. pub fn display_linux() -> &'static str { r#" .88888888:. diff --git a/src/fake.rs b/src/fake.rs index 3f867c7..0fe5e1a 100644 --- a/src/fake.rs +++ b/src/fake.rs @@ -1,681 +1,75 @@ -use std::{ - borrow::Cow, - ffi::{c_void, CStr, OsString}, - io::{Error, ErrorKind}, - mem, - os::{ - raw::{c_char, c_int}, - unix::ffi::OsStringExt, - }, -}; -#[cfg(target_os = "macos")] -use std::{ - os::{ - raw::{c_long, c_uchar}, - unix::ffi::OsStrExt, - }, - ptr::null_mut, -}; +//! Currently used for WebAssembly unknown (non-web) only -use crate::{Arch, DesktopEnv, Platform, Result}; - -#[repr(C)] -struct PassWd { - pw_name: *const c_void, - pw_passwd: *const c_void, - pw_uid: u32, - pw_gid: u32, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_change: isize, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_class: *const c_void, - pw_gecos: *const c_void, - pw_dir: *const c_void, - pw_shell: *const c_void, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_expire: isize, - #[cfg(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" - ))] - pw_fields: i32, -} - -extern "system" { - fn getpwuid_r( - uid: u32, - pwd: *mut PassWd, - buf: *mut c_void, - buflen: usize, - result: *mut *mut PassWd, - ) -> i32; - fn geteuid() -> u32; - fn gethostname(name: *mut c_void, len: usize) -> i32; -} - -#[cfg(target_os = "macos")] -#[link(name = "CoreFoundation", kind = "framework")] -#[link(name = "SystemConfiguration", kind = "framework")] -extern "system" { - fn CFStringGetCString( - the_string: *mut c_void, - buffer: *mut u8, - buffer_size: c_long, - encoding: u32, - ) -> c_uchar; - fn CFStringGetLength(the_string: *mut c_void) -> c_long; - fn CFStringGetMaximumSizeForEncoding( - length: c_long, - encoding: u32, - ) -> c_long; - fn SCDynamicStoreCopyComputerName( - store: *mut c_void, - encoding: *mut u32, - ) -> *mut c_void; - fn CFRelease(cf: *const c_void); -} - -unsafe fn strlen(cs: *const c_void) -> usize { - let mut len = 0; - let mut cs: *const u8 = cs.cast(); - while *cs != 0 { - len += 1; - cs = cs.offset(1); - } - len -} - -unsafe fn strlen_gecos(cs: *const c_void) -> usize { - let mut len = 0; - let mut cs: *const u8 = cs.cast(); - while *cs != 0 && *cs != b',' { - len += 1; - cs = cs.offset(1); - } - len -} - -// Convert an OsString into a String -fn string_from_os(string: OsString) -> String { - match string.into_string() { - Ok(string) => string, - Err(string) => string.to_string_lossy().to_string(), - } -} - -fn os_from_cstring_gecos(string: *const c_void) -> Result { - if string.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } +#[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] +compile_error!("Unexpected pointer width for target platform"); - // Get a byte slice of the c string. - let slice = unsafe { - let length = strlen_gecos(string); +use std::ffi::OsString; - if length == 0 { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - std::slice::from_raw_parts(string.cast(), length) - }; - - // Turn byte slice into Rust String. - Ok(OsString::from_vec(slice.to_vec())) -} - -fn os_from_cstring(string: *const c_void) -> Result { - if string.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - // Get a byte slice of the c string. - let slice = unsafe { - let length = strlen(string); - - if length == 0 { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - std::slice::from_raw_parts(string.cast(), length) - }; - - // Turn byte slice into Rust String. - Ok(OsString::from_vec(slice.to_vec())) -} - -#[cfg(target_os = "macos")] -fn os_from_cfstring(string: *mut c_void) -> OsString { - if string.is_null() { - return "".to_string().into(); - } - - unsafe { - let len = CFStringGetLength(string); - let capacity = - CFStringGetMaximumSizeForEncoding(len, 134_217_984 /* UTF8 */) + 1; - let mut out = Vec::with_capacity(capacity as usize); - if CFStringGetCString( - string, - out.as_mut_ptr(), - capacity, - 134_217_984, /* UTF8 */ - ) != 0 - { - out.set_len(strlen(out.as_ptr().cast())); // Remove trailing NUL byte - out.shrink_to_fit(); - CFRelease(string); - OsString::from_vec(out) - } else { - CFRelease(string); - "".to_string().into() - } - } -} +use crate::{Arch, DesktopEnv, Platform, Result}; -// This function must allocate, because a slice or Cow would still -// reference `passwd` which is dropped when this function returns. #[inline(always)] -fn getpwuid(real: bool) -> Result { - const BUF_SIZE: usize = 16_384; // size from the man page - let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit(); - let mut passwd = mem::MaybeUninit::::uninit(); - let mut _passwd = mem::MaybeUninit::<*mut PassWd>::uninit(); - - // Get PassWd `struct`. - let passwd = unsafe { - let ret = getpwuid_r( - geteuid(), - passwd.as_mut_ptr(), - buffer.as_mut_ptr() as *mut c_void, - BUF_SIZE, - _passwd.as_mut_ptr(), - ); - - if ret != 0 { - return Err(Error::last_os_error()); - } - - let _passwd = _passwd.assume_init(); - - if _passwd.is_null() { - return Err(Error::new(ErrorKind::NotFound, "Null record")); - } - - passwd.assume_init() - }; - - // Extract names. - if real { - os_from_cstring_gecos(passwd.pw_gecos) - } else { - os_from_cstring(passwd.pw_name) - } -} - -pub(crate) fn username() -> Result { - Ok(string_from_os(username_os()?)) +pub(crate) fn lang() -> impl Iterator { + std::iter::once("en-US".to_string()) } +#[inline(always)] pub(crate) fn username_os() -> Result { - getpwuid(false) -} - -pub(crate) fn realname() -> Result { - Ok(string_from_os(realname_os()?)) + Ok(username()?.into()) } +#[inline(always)] pub(crate) fn realname_os() -> Result { - getpwuid(true) + Ok(realname()?.into()) } -#[cfg(not(target_os = "macos"))] +#[inline(always)] pub(crate) fn devicename_os() -> Result { Ok(devicename()?.into()) } -#[cfg(not(any(target_os = "macos", target_os = "illumos")))] -pub(crate) fn devicename() -> Result { - let machine_info = std::fs::read("/etc/machine-info")?; - let machine_info = String::from_utf8_lossy(&machine_info); - - for i in machine_info.split('\n') { - let mut j = i.split('='); - - if j.next() == Some("PRETTY_HOSTNAME") { - if let Some(value) = j.next() { - // FIXME: Can " be escaped in pretty name? - return Ok(value.trim_matches('"').to_string()); - } - } - } - - Err(Error::new(ErrorKind::NotFound, "Missing record")) -} - -#[cfg(target_os = "macos")] -pub(crate) fn devicename() -> Result { - Ok(string_from_os(devicename_os()?)) -} - -#[cfg(target_os = "macos")] -pub(crate) fn devicename_os() -> Result { - let out = os_from_cfstring(unsafe { - SCDynamicStoreCopyComputerName(null_mut(), null_mut()) - }); - - if out.as_bytes().is_empty() { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - Ok(out) -} - -#[cfg(target_os = "illumos")] -pub(crate) fn devicename() -> Result { - let program = std::fs::read("/etc/nodename")?; - let mut nodename = String::from_utf8_lossy(&program).to_string(); - // Remove the trailing newline - let _ = nodename.pop(); - - if nodename.is_empty() { - return Err(Error::new(ErrorKind::InvalidData, "Empty record")); - } - - Ok(nodename) -} - -pub(crate) fn hostname() -> Result { - Ok(string_from_os(hostname_os()?)) -} - -fn hostname_os() -> Result { - // Maximum hostname length = 255, plus a NULL byte. - let mut string = Vec::::with_capacity(256); - - unsafe { - if gethostname(string.as_mut_ptr() as *mut c_void, 255) == -1 { - return Err(Error::last_os_error()); - } - - string.set_len(strlen(string.as_ptr() as *const c_void)); - }; - - Ok(OsString::from_vec(string)) -} - -#[cfg(target_os = "macos")] -fn distro_xml(data: String) -> Result { - let mut product_name = None; - let mut user_visible_version = None; - - if let Some(start) = data.find("") { - if let Some(end) = data.find("") { - let mut set_product_name = false; - let mut set_user_visible_version = false; - - for line in data[start + "".len()..end].lines() { - let line = line.trim(); - - if line.starts_with("") { - match line["".len()..].trim_end_matches("") { - "ProductName" => set_product_name = true, - "ProductUserVisibleVersion" => { - set_user_visible_version = true - } - "ProductVersion" => { - if user_visible_version.is_none() { - set_user_visible_version = true - } - } - _ => {} - } - } else if line.starts_with("") { - if set_product_name { - product_name = Some( - line["".len()..] - .trim_end_matches(""), - ); - set_product_name = false; - } else if set_user_visible_version { - user_visible_version = Some( - line["".len()..] - .trim_end_matches(""), - ); - set_user_visible_version = false; - } - } - } - } - } - - Ok(if let Some(product_name) = product_name { - if let Some(user_visible_version) = user_visible_version { - format!("{} {}", product_name, user_visible_version) - } else { - product_name.to_string() - } - } else { - user_visible_version - .map(|v| format!("Mac OS (Unknown) {}", v)) - .ok_or_else(|| { - Error::new(ErrorKind::InvalidData, "Parsing failed") - })? - }) -} - -#[cfg(target_os = "macos")] -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -#[cfg(target_os = "macos")] -pub(crate) fn distro() -> Result { - if let Ok(data) = std::fs::read_to_string( - "/System/Library/CoreServices/ServerVersion.plist", - ) { - distro_xml(data) - } else if let Ok(data) = std::fs::read_to_string( - "/System/Library/CoreServices/SystemVersion.plist", - ) { - distro_xml(data) - } else { - Err(Error::new(ErrorKind::NotFound, "Missing record")) - } -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn distro_os() -> Result { - distro().map(|a| a.into()) -} - -#[cfg(not(target_os = "macos"))] -pub(crate) fn distro() -> Result { - let program = std::fs::read("/etc/os-release")?; - let distro = String::from_utf8_lossy(&program); - let err = || Error::new(ErrorKind::InvalidData, "Parsing failed"); - let mut fallback = None; - - for i in distro.split('\n') { - let mut j = i.split('='); - - match j.next().ok_or_else(err)? { - "PRETTY_NAME" => { - return Ok(j - .next() - .ok_or_else(err)? - .trim_matches('"') - .to_string()); - } - "NAME" => { - fallback = Some( - j.next().ok_or_else(err)?.trim_matches('"').to_string(), - ) - } - _ => {} - } - } - - fallback.ok_or_else(err) -} - -#[cfg(target_os = "macos")] #[inline(always)] -pub(crate) const fn desktop_env() -> DesktopEnv { - DesktopEnv::Aqua +pub(crate) fn distro_os() -> Result { + Ok(distro()?.into()) } -#[cfg(not(target_os = "macos"))] #[inline(always)] -pub(crate) fn desktop_env() -> DesktopEnv { - match std::env::var_os("DESKTOP_SESSION") - .map(|env| env.to_string_lossy().to_string()) - { - Some(env_orig) => { - let env = env_orig.to_uppercase(); - - if env.contains("GNOME") { - DesktopEnv::Gnome - } else if env.contains("LXDE") { - DesktopEnv::Lxde - } else if env.contains("OPENBOX") { - DesktopEnv::Openbox - } else if env.contains("I3") { - DesktopEnv::I3 - } else if env.contains("UBUNTU") { - DesktopEnv::Ubuntu - } else if env.contains("PLASMA5") { - DesktopEnv::Kde - } else { - DesktopEnv::Unknown(env_orig) - } - } - // TODO: Other Linux Desktop Environments - None => DesktopEnv::Unknown("Unknown".to_string()), - } +pub(crate) fn username() -> Result { + Ok("anonymous".to_string()) } -#[cfg(target_os = "macos")] #[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::MacOS +pub(crate) fn realname() -> Result { + Ok("Anonymous".to_string()) } -#[cfg(not(any( - target_os = "macos", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd", - target_os = "illumos" -)))] #[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Linux +pub(crate) fn devicename() -> Result { + Ok("Unknown".to_string()) } -#[cfg(any( - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "openbsd", - target_os = "netbsd" -))] #[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Bsd +pub(crate) fn hostname() -> Result { + Ok("localhost".to_string()) } -#[cfg(target_os = "illumos")] #[inline(always)] -pub(crate) const fn platform() -> Platform { - Platform::Illumos -} - -struct LangIter { - array: String, - index: Option, -} - -impl Iterator for LangIter { - type Item = String; - - fn next(&mut self) -> Option { - if self.index? && self.array.contains('-') { - self.index = Some(false); - let mut temp = self.array.split('-').next()?.to_string(); - mem::swap(&mut temp, &mut self.array); - Some(temp) - } else { - self.index = None; - let mut temp = String::new(); - mem::swap(&mut temp, &mut self.array); - Some(temp) - } - } +pub(crate) fn distro() -> Result { + Ok("Emulated".to_string()) } #[inline(always)] -pub(crate) fn lang() -> impl Iterator { - const DEFAULT_LANG: &str = "en_US"; - - let array = std::env::var("LANG") - .unwrap_or_default() - .split('.') - .next() - .unwrap_or(DEFAULT_LANG) - .to_string(); - let array = if array == "C" { - DEFAULT_LANG.to_string() - } else { - array - }; - - LangIter { - array: array.replace('_', "-"), - index: Some(true), - } -} - -#[repr(C)] -#[cfg(any( - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "netbsd", - target_os = "openbsd", - target_os = "illumos" -))] -struct UtsName { - #[cfg(not(target_os = "dragonfly"))] - sysname: [c_char; 256], - #[cfg(target_os = "dragonfly")] - sysname: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - nodename: [c_char; 256], - #[cfg(target_os = "dragonfly")] - nodename: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - release: [c_char; 256], - #[cfg(target_os = "dragonfly")] - release: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - version: [c_char; 256], - #[cfg(target_os = "dragonfly")] - version: [c_char; 32], - #[cfg(not(target_os = "dragonfly"))] - machine: [c_char; 256], - #[cfg(target_os = "dragonfly")] - machine: [c_char; 32], -} - -#[repr(C)] -#[cfg(any( - target_os = "linux", - target_os = "android", - target_os = "fuchsia", - target_os = "redox" -))] -struct UtsName { - sysname: [c_char; 65], - nodename: [c_char; 65], - release: [c_char; 65], - version: [c_char; 65], - machine: [c_char; 65], - domainname: [c_char; 65], -} - -// Buffer initialization -impl Default for UtsName { - fn default() -> Self { - unsafe { mem::zeroed() } - } +pub(crate) fn desktop_env() -> DesktopEnv { + DesktopEnv::Unknown("WebAssembly".to_string()) } -extern "C" { - #[cfg(not(target_os = "freebsd"))] - fn uname(buf: *mut UtsName) -> c_int; - - #[cfg(target_os = "freebsd")] - fn __xuname(nmln: c_int, buf: *mut c_void) -> c_int; -} -#[inline] -#[cfg(target_os = "freebsd")] -unsafe extern "C" fn uname(buf: *mut UtsName) -> c_int { - __xuname(256, buf.cast()) -} - -impl Arch { - fn from_str(s: Cow<'_, str>) -> Self { - let arch_str = match s { - Cow::Borrowed(str) => str, - Cow::Owned(ref str) => str, - }; - match arch_str { - "aarch64" | "arm64" | "aarch64_be" | "armv8b" | "armv8l" => { - Arch::Arm64 - } - "armv5" => Arch::ArmV5, - "armv6" | "arm" => Arch::ArmV6, - "armv7" => Arch::ArmV7, - "i386" => Arch::I386, - "i586" => Arch::I586, - "i686" | "i686-AT386" => Arch::I686, - "mips" => Arch::Mips, - "mipsel" => Arch::MipsEl, - "mips64" => Arch::Mips64, - "mips64el" => Arch::Mips64El, - "powerpc" | "ppc" | "ppcle" => Arch::PowerPc, - "powerpc64" | "ppc64" | "ppc64le" => Arch::PowerPc64, - "powerpc64le" => Arch::PowerPc64Le, - "riscv32" => Arch::Riscv32, - "riscv64" => Arch::Riscv64, - "s390x" => Arch::S390x, - "sparc" => Arch::Sparc, - "sparc64" => Arch::Sparc64, - "wasm32" => Arch::Wasm32, - "wasm64" => Arch::Wasm64, - "x86_64" | "amd64" => Arch::X64, - _ => Arch::Unknown(arch_str.to_owned()), - } - } +pub(crate) fn platform() -> Platform { + Platform::Unknown("Unknown".to_string()) } pub(crate) fn arch() -> Arch { - let mut buf = UtsName::default(); - let result = unsafe { uname(&mut buf) }; - if result == -1 { - return Arch::Unknown("uname(2) failed to execute".to_owned()); + if cfg!(target_pointer_width = "64") { + Arch::Wasm64 + } else { + Arch::Wasm32 } - - let arch_str = - unsafe { CStr::from_ptr(buf.machine.as_ptr()) }.to_string_lossy(); - - Arch::from_str(arch_str) } From 73c2cb50dbfa84a5387a380da0599f482faf6d88 Mon Sep 17 00:00:00 2001 From: sebihutanu1 Date: Tue, 23 Jan 2024 19:20:30 +0200 Subject: [PATCH 7/7] Fix more Clippy errors --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 8f5139d..ae3b769 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,6 +71,7 @@ const DEFAULT_USERNAME: &str = "Unknown"; const DEFAULT_HOSTNAME: &str = "LocalHost"; +#[allow(missing_docs)] pub mod disp; pub mod fallible;