Compare commits

..

895 Commits

Author SHA1 Message Date
Carter Li 7a2bf4e0ac Merge pull request #2049 from fastfetch-cli/dev
Releases: v2.55.0
2025-11-11 18:51:24 +08:00
李通洲 662f5127fa Shell: makes fish shell version detection more robust (v2) 2025-11-11 15:38:53 +08:00
李通洲 fb9117553b Shell: makes fish shell version detection more robust 2025-11-11 15:19:40 +08:00
李通洲 9f24e4363f Media (Linux): handles invalid percent-encoding in cover metadata 2025-11-11 15:16:12 +08:00
李通洲 084f9294f2 Media: updates naming convention from mediacover to media-cover for media cover logo sources 2025-11-11 14:42:55 +08:00
李通洲 a9f1f9a647 Doc: update changelog 2025-11-11 14:31:23 +08:00
李通洲 0aed89036b Chore: silenses some compiler warnings 2025-11-11 14:24:32 +08:00
李通洲 df15bbc5f2 Media: moves media cover cleanup logic to media detection 2025-11-11 14:00:43 +08:00
李通洲 e6b0bd3817 Media: fixes album cover serialization in JSON result 2025-11-11 13:58:45 +08:00
李通洲 11cd7153a2 Logo (Builtin): tidy [ci skip] 2025-11-11 13:53:34 +08:00
李通洲 f8bc1cb605 Releases: v2.55.0 2025-11-11 11:01:54 +08:00
李通洲 8b8eb6f290 TerminalShell (Linux): ignores run-parts
Ref: #2048
2025-11-11 10:10:47 +08:00
李通洲 056fe21ee2 Examples/25: removes parallel: true since we had it enabled by default [ci skip] 2025-11-11 10:07:58 +08:00
Carter Li cb0a88df22 [Command] enables parallel command execution by default 2025-11-11 09:28:44 +08:00
Carter Li 298c0431c3 Examples: improves clang version extraction method in 25.jsonc [ci skip] 2025-11-11 09:00:01 +08:00
Carter Li 448de9afa5 Command: makes compiler happy 2025-11-10 22:48:22 +08:00
Carter Li 9401a4b9ad Processing: adds a missing header 2025-11-10 18:09:19 +08:00
李通洲 ea92ad3785 Command: adds parallel and useStdErr options
Fixes #2045
2025-11-10 16:34:23 +08:00
李通洲 7aaad5e03e Processing: refactors process execution to separate spawning and reading 2025-11-10 16:34:23 +08:00
李通洲 645bf5c839 Disk: moves disk hiding by folder and FS type to detection code
Don't probe if hided

Fixes #2043
2025-11-06 13:39:30 +08:00
李通洲 7638e0e4a1 CMake: improves wordexp/glob detection and messaging 2025-11-05 10:21:05 +08:00
李通洲 302b8a7b1b CommandLine: adds dynamic output refresh support with interval option 2025-11-05 10:21:05 +08:00
李通洲 dbb9d8a660 Display: adds missing #include 2025-11-05 09:59:27 +08:00
李通洲 c51a164042 PublicIP / Weather: cleans up states after detection 2025-11-05 09:56:23 +08:00
李通洲 6b8a62da6e Linux (Host): improves Mac family detection by using prefix match 2025-11-04 09:12:35 +08:00
李通洲 578ca23e75 GPU (Hurd): adds support (requires libpciaccess) 2025-11-01 09:57:52 +00:00
李通洲 2e73a90835 GPU (OpenBSD): adds native GPU detection support 2025-11-01 17:23:59 +08:00
李通洲 cc6273fecc GPU (NetBSD): don't use system function name 2025-11-01 17:19:25 +08:00
李通洲 e63b777916 GPU: handles missing GPU type as null in JSON output 2025-11-01 16:44:36 +08:00
李通洲 907567f511 GPU (NetBSD): improves performance; drops libpciaccess dependency 2025-11-01 16:42:19 +08:00
李通洲 e0fd7308be Logo (Builtin): add Vincent OS
Fixes #2030
2025-10-31 11:04:18 +08:00
李通洲 b761034aae OS (Linux): prints debian version on Raspbery Pi OS
Fixes #2032
2025-10-31 11:04:18 +08:00
李通洲 04d6b1453d GPU (NetBSD): adds native GPU detection support 2025-10-31 11:04:18 +08:00
Carter Li 11d1754686 GPU: skips auxiliary display controllers
Fixes #2034
2025-10-30 14:46:30 +08:00
Carter Li 25e84decff GPU: unifies non-pci GPU device ID formatting across platforms 2025-10-30 11:01:06 +08:00
Carter Li 7d665b203f GPU: unifies GPU PCI device ID calculation logic across different platforms 2025-10-30 10:26:35 +08:00
李通洲 ac62442798 CMake: refines yyjson config and Apple rpath handling
Fixes #1998
2025-10-28 09:30:46 +08:00
李通洲 758f96de60 Icons (Windows): hides module when no icons are found
Fixes #2023
2025-10-24 14:46:09 +08:00
李通洲 db623b9c86 CI (Linux): adds Debian i386 packaging and verify deb package in CI
Fixes #2019
2025-10-22 17:45:50 +08:00
李通洲 c353bf3c96 Logo: adds automatic cleanup of temporary media cover files 2025-10-22 13:51:36 +08:00
李通洲 338b552499 Logo: adds support for using media cover as logo source 2025-10-21 15:05:25 +08:00
李通洲 5d73cc1232 Media: save media cover to temp file 2025-10-21 14:36:35 +08:00
李通洲 faddef7a3b Media (Windows): adds media cover extraction 2025-10-21 14:01:26 +08:00
Carter Li 2d9bbc8049 Media (Linux): adds media cover extraction 2025-10-21 09:44:36 +08:00
李通洲 64afaa07e7 Media (macOS): adds media cover extraction 2025-10-21 09:44:36 +08:00
李通洲 5cf3ab23b0 Utils (macOS): adds ffCfDictGetDataAsString 2025-10-21 08:49:34 +08:00
李通洲 3fe926d3a0 Doc: adds code-signing credit and privacy statement in README [ci skip]
As required by signpath
2025-10-20 23:43:32 +08:00
李通洲 f71bb682de Logo (Builtin): adds MacaroniOS
Fixes #2018
2025-10-20 15:12:11 +08:00
Carter Li 904f860f3c Packaging: builds for all Ubuntu versions [ci skip] 2025-10-20 14:58:23 +08:00
Carter Li 8f15c9604c Merge remote-tracking branch 'origin/master' into dev 2025-10-20 14:57:59 +08:00
李通洲 ff28f5807b Shell: supports brush version detection 2025-10-19 10:25:28 +08:00
李通洲 6a317366d7 Shell: fix fish version detection when LC_ALL is set
Fixes #2014
2025-10-19 10:25:28 +08:00
李通洲 dc3e4a2d18 JsonSchema: fixes copy-paste errors [ci skip]
Fixes #2013
2025-10-18 18:38:39 +08:00
Carter Li 46c4a71ba3 Merge pull request #2012 from fastfetch-cli/dev
Release: v2.54.0
2025-10-18 10:15:23 +08:00
Carter Li f0759acd11 Brightness (macOS): tidy 2025-10-18 09:35:34 +08:00
李通洲 96c7c2966d Brightness (macOS): prioritizes DDC/CI reply over simple I²C transaction 2025-10-18 01:11:03 +08:00
李通洲 554e7bce4a Logo (Builtin): adds Zraxyl
Fixes #1860
2025-10-18 00:56:14 +08:00
李通洲 70377a8afd Release: v2.54.0 2025-10-18 00:47:35 +08:00
李通洲 51bc6d421a CI (Windows): switches CI to use the release signing policy on the master branch 2025-10-18 00:47:35 +08:00
李通洲 be0756f8ba CMake: adds a new build option to gate wordexp usage and detection 2025-10-16 15:29:24 +08:00
李通洲 71a2cb4e1b Doc: adds security warning for Command module in README 2025-10-16 14:34:51 +08:00
李通洲 2eba761bed IO (OpenBSD): fixes incorrect glob usage 2025-10-16 14:33:53 +08:00
李通洲 4b5e1a816b Display (Windows): rename VRR to DRR 2025-10-16 13:24:44 +08:00
Dariqq a92e4b2d67 Chore (Windows): standardize more windows header casing.
Followup to 25353261d0
2025-10-14 15:49:06 +08:00
李通洲 a32404ba98 Doc: updates changelog 2025-10-14 14:51:44 +08:00
李通洲 0a792e4935 CPU (Android): adds detection support for Samsung Exynos SoCs 2025-10-14 14:49:29 +08:00
李通洲 05108977e8 CPU (Android): improves Android SoC vendor and model detection 2025-10-14 14:49:29 +08:00
李通洲 25353261d0 Chore (Windows): standardizes Windows header include casing. NOOP.
Fixes #2006
2025-10-14 09:10:24 +08:00
李通洲 4b517263d0 Chore (macOS): refactors code for better resource management 2025-10-13 14:27:23 +08:00
李通洲 98a65966e7 Doc: update changelog [ci skip] 2025-10-13 10:19:22 +08:00
李通洲 32dcf9487f Option: adds configurable spacing between icon and string keys
Fixes #2004
2025-10-13 09:54:34 +08:00
Carter Li e3a698f7b1 Brightness (macOS): fixes detection for external monitor on Intel platform 2025-10-11 21:26:37 +08:00
李通洲 1631f74700 Disk (Linux): revisits 78c6d71049 2025-10-11 18:20:56 +08:00
李通洲 78c6d71049 Disk (Linux): adds glob pattern matching for hidden disk folders
Fixes #1999
2025-10-11 16:19:11 +08:00
李通洲 0b9ecdeade Doc: adds Chinese README [ci skip] 2025-10-11 09:31:59 +08:00
李通洲 185a9211f1 Doc: update changelog 2025-10-10 15:09:25 +08:00
李通洲 24459b2fbf Brightness (macOS): enhance DDC/CI detection by enumerating all I2C buses 2025-10-10 14:24:11 +08:00
Carter Li 88c8dcb3e8 CPU (Linux): improves detection for T-Head CPU vendor
Ref: #1997
2025-10-10 10:55:12 +08:00
Carter Li f3a8fedf0a CPU (Linux): improves SoC name detection from device tree
Fixes #1997
2025-10-10 10:50:20 +08:00
李通洲 6b8b7c1a62 CI (Windows): signs PE files 2025-10-08 00:39:22 +08:00
李通洲 af26828f91 CPU (Linux): adds support for HP PA‑RISC & SuperH CPU architecture detection 2025-10-05 09:22:06 +08:00
李通洲 f4c43abbf7 Display (Windows): adds VRR status detection support 2025-10-05 09:17:30 +08:00
李通洲 e84739bff0 Logo (Builtin): update T2 2025-10-05 09:15:59 +08:00
李通洲 66aad0e4f1 Revert "Display (Windows): fixes incorrect refresh rate when VRR is enabled"
Doesn't work

This reverts commit 31ae7a642a.
2025-10-05 00:16:49 +08:00
Carter Li 77c43c0214 Display (Linux): prefer resolutions reported by randr mode info 2025-10-04 22:19:25 +08:00
李通洲 31ae7a642a Display (Windows): fixes incorrect refresh rate when VRR is enabled
Fixes #1994
2025-10-03 23:42:57 +08:00
Carter Li 1bbb21486c Disk (Linux): f* Android
Fixes #1993
2025-10-03 16:53:09 +08:00
李通洲 316d8ddf9b CI (Linux): disables post operations for polyfilled binaries
Fixes #1990
2025-10-03 12:16:15 +08:00
Carter Li 5d8c21a5ca Memory (Linux): fallbacks to calcuate ourselves when MemAvailable seems unreasonable
Fixes #1988
2025-10-02 07:39:20 +08:00
李通洲 240ba5c00c Platform (Windows): adds missing else for Wine version detection 2025-10-01 16:45:13 +08:00
Carter Li 554184ec72 OS (Windows): restores compatibility with WINE
Revert "OS (Windows): hard linking winbrand"

This reverts commit 4146bb6731.
2025-10-01 16:12:45 +08:00
李通洲 7a055a2254 CI: upgrades compiler versions 2025-10-01 10:07:28 +08:00
Carter Li 0a807ac1a3 TerminalFont (Linux): fixes default font size for ghostty
Fixes #1986
2025-10-01 08:09:04 +08:00
Carter Li 4d831c8c73 OS (Linux): don't change prettyName on Ubuntu development branch
Ref: #1483
2025-09-30 15:24:52 +08:00
李通洲 e6e78a7aae OS (macOS): improves OS detection accuracy and sets pretty name 2025-09-30 13:35:48 +08:00
李通洲 09bef5f41d OS (macOS): removes fallback parsing of legacy macOS license file
Doesn't work on Tahoe anymore
2025-09-30 13:22:00 +08:00
李通洲 e394efdd85 OS (macOS): trims whitespace from full user name 2025-09-30 13:19:58 +08:00
李通洲 c10b652a2e Swap (Windows): prevents integer overflow in swap size
Regression from 7ec0c664c5
2025-09-30 10:05:08 +08:00
李通洲 1594a69d6c Kernel (Windows): move kernel.displayVersion to OS.codeName 2025-09-30 10:01:01 +08:00
李通洲 9b1e318bd1 OS (Linux): sets code name for Ubuntu 2025-09-30 09:09:36 +08:00
李通洲 e292bf1dee OS (Linux): sets point release for Debian
Fixes #1985
2025-09-30 09:06:12 +08:00
李通洲 55a0c6e97d Logo (Builtin): adds EmperorOS
Fixes #1963
2025-09-29 10:07:26 +08:00
Rain Xelelo 8b8e4a40a4 Logo (Builtin): adds PrismLinux
Fixes #1983
2025-09-28 21:01:03 -05:00
李通洲 8be070998f Theme (Windows): moves Windows theme detection logic from DE to dedicated module
Like the last commit
2025-09-29 09:40:10 +08:00
李通洲 093f56a03d Theme (macOS): moves macOS theme detection logic from DE to dedicated module
The old behavior was inherited from neofetch. However `Aqua` and `Liquid Glass` are actually design language, not a DE. There is no DE on macOS.
2025-09-29 09:25:24 +08:00
李通洲 bd9744c27c CommandLine: adds --json flag as a shortcut for enabling JSON output 2025-09-28 15:07:45 +08:00
李通洲 adc25f4420 CI: adds Debian libc6 dependency to package config
Fixes #1981
2025-09-28 14:43:38 +08:00
李通洲 229fe7c7bf CMake: update contact info 2025-09-28 14:43:38 +08:00
李通洲 5d571752ae Chore: updates FUNDING info 2025-09-28 14:43:38 +08:00
李通洲 512ddfae6b Doc: adds padding check to logo request template 2025-09-28 09:40:48 +08:00
李通洲 7b689f94df Logo (Builtin): adds secureblue
Fixes #1979
2025-09-28 09:40:21 +08:00
李通洲 9eed149b09 CMake (Linux): adds i686 CI build and unify processor naming
Fixes #1978
2025-09-25 16:30:59 +08:00
李通洲 0f5d321df8 Chore: updates comments to use English descriptions 2025-09-24 10:11:02 +08:00
李通洲 4e84094fd8 CI (OpenBSD): updates CI workflow to upgrade packages before install 2025-09-23 16:41:18 +08:00
李通洲 7b9fce0189 CI (Linux): adds GCC 13 toolchain to CI build environment 2025-09-23 16:00:45 +08:00
李通洲 9ab5c33008 CI: fix release action 2025-09-23 10:19:55 +08:00
Carter Li 613b1d63f1 Packaging: updates debian stuff [ci skip] 2025-09-23 10:03:30 +08:00
Carter Li 8c86cafec7 Merge pull request #1976 from fastfetch-cli/dev
Release: v2.53.0
2025-09-23 09:55:28 +08:00
李通洲 4098cf51b3 Release: v2.53.0 2025-09-23 09:27:52 +08:00
李通洲 bfc23232f8 CPU (Android): adds support for new Qualcomm and MediaTek SoC codes 2025-09-23 09:13:10 +08:00
李通洲 483fba44dc Doc: update changelog [ci skip] 2025-09-22 16:40:10 +08:00
李通洲 851751f99d CPU (Linux): adds support for new ARM C1 series CPU part IDs
Follows changes of util-linux
2025-09-22 16:24:36 +08:00
李通洲 3e86130ddd Zpool: increase libzfs so version to 6
Fixes #1973
2025-09-22 14:32:19 +08:00
李通洲 350ffced13 CI: upgrades runner of intel macOS 2025-09-22 14:13:41 +08:00
李通洲 cdcdb78b97 CPU (Windows): refines ARMv8.4-A detection to require LSE2 2025-09-22 14:08:29 +08:00
Osama Albahrani 2ae9d01200 OS (Linux): Better Ubuntu flavor detection
- Fixes https://github.com/fastfetch-cli/fastfetch/issues/1974
2025-09-22 10:04:45 +08:00
李通洲 e95393750b Wifi (macOS): add (B)SSID detection back for Tohoe 26.0
Fixes #1874
2025-09-22 09:37:07 +08:00
李通洲 de9229697a TerminalFont: improve ghostty with command ghostty +show-config
Ref: #1972
2025-09-20 23:34:07 +08:00
NEOAPPS 9d23d28594 Logo (Builtin): update ObsidianOS logo (#1970)
* feat(logos): add new ObsidianOS logo

* feat(logos): update colors

* chore: remove internal paddings since they're not allowed
2025-09-20 23:02:25 +08:00
李通洲 57a4b9b6ed Disk: refactors mountpoint matching to use shared string utilities 2025-09-19 14:54:13 +08:00
李通洲 ef3989d18d CommandOption: refactors code with ffStrbufSeparatedContainIgnCaseS 2025-09-19 14:51:31 +08:00
李通洲 3079b44f63 FFstrbuf: adds more functions to match separated strings
1. ffStrbufMatchSeparatedIgnCaseNS
2. ffStrbufSeparatedContainNS
3. ffStrbufSeparatedContainNS
2025-09-19 14:34:27 +08:00
李通洲 403900639c Gamepad / Keyboard / Mouse: improves device error handling and memory cleanup 2025-09-19 13:36:02 +08:00
李通洲 0bb5b4cc9c Gamepad / Keyboard / Mouse: adds support to ignore input devices by name prefix
Fixes #1950
2025-09-19 11:00:18 +08:00
李通洲 1180eb55a4 Logo (Builtin): adds TempleOS
Fixes #1969
2025-09-19 09:46:23 +08:00
李通洲 f0e9caaf04 Disk: allows array input for disk folder and filesystem options 2025-09-18 14:51:00 +08:00
李通洲 2c22c3b0c0 CI (Windows): add chafa dependency 2025-09-18 13:44:51 +08:00
李通洲 e9065e15e8 TerminalFont: Improves Ghostty font config parsing with fallback font detection
Fixes #1967
2025-09-18 10:30:28 +08:00
李通洲 9e7816069b Revert "Logo (Builtin): add Starry Linux"
Ref: #1963

This reverts commit 4df4a1de78.
2025-09-17 16:09:05 +08:00
李通洲 82cdc4cd91 Disk (Linux): avoids invalid disk creation times before Linux epoch
Prevent fastfetch from printing invalid create date on Android
2025-09-17 15:37:51 +08:00
Carter Li 822ddc6dc6 Disk (Linux): replace statx(2) call to syscall(2) 2025-09-17 15:09:39 +08:00
李通洲 8bd171a9ff CI: adds glibc polyfill step for compatibility 2025-09-17 14:28:40 +08:00
李通洲 509d6bf30c CI: merge more jobs 2025-09-17 14:00:23 +08:00
李通洲 ab8a13b2d3 CI: update cmake version 2025-09-17 10:39:59 +08:00
Carter Li 3bcdcc5dbf CI: merge amd64 and aarch64 code with matrix 2025-09-16 16:28:45 +08:00
李通洲 38f4215a94 CPU (Windows): trims vendor string read from registry 2025-09-16 10:55:17 +08:00
李通洲 e3eec3f62a CPU (Windows): handles zero temperature data and refactors value use
Fixes #1960
2025-09-14 19:39:17 +08:00
李通洲 e025f28cdc Wifi (macOS): removes wdutil-based Wi-Fi detection code
Let's stop this hide and seek game.
2025-09-12 14:28:01 +08:00
李通洲 3ece4e3b4d Presets: add a new example [ci skip] 2025-09-12 14:11:41 +08:00
Carter Li 6d72a32d1d 3rdparty: upgrade widecharwidth 2025-09-11 14:54:25 +08:00
Carter Li 45be29bad3 CPU (Linux): replaces HWCAP defines with explicit bitmasks for ARM 2025-09-11 14:02:41 +08:00
李通洲 6f5e618341 CPU (Linux): add new ARM part numbers 2025-09-10 14:32:07 +08:00
李通洲 1abfa70237 LocalIP: adds IPv6 type selection for local IP display
`{ "type": "localip", "showIpv6": "ula" /* Show ULA only */ }`

Fixes #1459
2025-09-10 13:42:48 +08:00
李通洲 baaeef5ab5 Separator: uses widecharwidth for Unicode wcwidth and fixes issue that wchar_t on Windows is 2-byte length 2025-09-10 10:34:07 +08:00
李通洲 8eafec479e Separator: rename property length with times 2025-09-09 09:52:10 +08:00
李通洲 5f9e7c799a OpenGL (Windows): simplifies code by removing custom window proc
Adds more cleanups
2025-09-08 00:06:49 +08:00
Carter Li aeb1722eb9 Packaging: update debian stuff [ci skip] 2025-09-05 15:12:49 +08:00
Carter Li de18a07938 Release: v2.52.0 2025-09-05 13:04:53 +08:00
李通洲 88147f80ac Doc: update changelog 2025-09-05 12:38:14 +08:00
李通洲 505ff6ff65 Global: renames fractionTrailingZeros enum to always/never for consistance 2025-09-05 12:27:03 +08:00
李通洲 390549394d Fastfetch: removes redundant assignment in display config parsing
found by copilot
2025-09-05 11:08:37 +08:00
Carter Li f7e7d54c16 Release: v2.52.0 2025-09-05 10:46:30 +08:00
Carter Li 5e068d22c8 Btrfs (Linux): refactors Btrfs allocation to use profile string
Fixes #1941
2025-09-05 10:46:23 +08:00
李通洲 b77646f23e Btrfs (Linux): adds tracking of Btrfs data copy counts
Fixes(?) #1941
2025-09-05 00:18:00 +08:00
李通洲 aa40366a49 Terminal: ignores WSL2 unknown process for terminal detection 2025-09-04 22:31:59 +08:00
Carter Li a64a82f215 WMTheme (Linux): supports labwc on XFCE4 2025-09-04 18:50:23 +08:00
Qing Yun 0a4d6220e9 CPU (Linux): add cpu name detection for ia64 2025-09-04 18:34:14 +08:00
李通洲 6b037c595f Doc: update README 2025-09-04 16:36:55 +08:00
李通洲 f628f5c382 Settings: renames GNOME settings accessor for clarity 2025-09-04 16:17:01 +08:00
李通洲 cf713e32e1 Wallpaper (Linux): improves XFCE wallpaper detection via property enumeration 2025-09-04 13:54:49 +08:00
Carter Li 7d08f81075 Settings: removes direct XFConf support in favor of DBus backend 2025-09-04 09:43:57 +08:00
Carter Li 8822653335 DBus: adds function ffDBusGetInt 2025-09-04 09:35:52 +08:00
李通洲 75ff054255 Dbus: adds 2nd argument to ffDBusGetMethodReply 2025-09-04 08:45:09 +08:00
李通洲 c51cc8ce6b CI: bump dependencies 2025-09-03 16:01:09 +08:00
李通洲 44e23412b5 Doc: update changelog 2025-09-03 16:01:09 +08:00
李通洲 59742bca00 Fastfetch: improves frequency display config validation and schema 2025-09-03 16:01:09 +08:00
李通洲 303edb97ce Fastfetch: add option --faction-trailing-zeros 2025-09-03 14:20:23 +08:00
李通洲 37ab380a6f Logo (Chafa): fixes setting logo.width with chafa
Regression in v2.51.0

Fixes #1947
2025-09-03 10:49:58 +08:00
Carter Li a06e245c34 JsonSchema: update 2025-09-03 09:58:50 +08:00
Carter Li 5de432b083 Fastfetch: defaults display.fraction.ndigits to 2 2025-09-03 09:58:40 +08:00
Carter Li 817285ac01 Fastfetch: informs users that module-specific CLI options are no longer supported
... and provides guidance on transitioning to JSON config
2025-09-03 09:36:16 +08:00
李通洲 8687505505 LocalIP (Linux): skips interfaces without IPs unless MAC display is enabled 2025-09-02 15:00:35 +08:00
李通洲 34c34d25c4 JsonConfig: fixes fractionNdigits will be incorrectly set to 0 when specifying null 2025-09-02 14:44:15 +08:00
李通洲 21b15ee944 Display: rearranges default format; removes scaled resolution 2025-09-02 14:15:37 +08:00
李通洲 8e0a65126e LocalIP: honors fractionTrailingZeros 2025-09-02 14:13:37 +08:00
李通洲 54d8b0a95d Global: adds configurable trailing zeros for double formatting 2025-09-02 14:12:58 +08:00
李通洲 48fc72e95c DisplayServer: improves display size rounding and argument clarity 2025-09-02 09:36:19 +08:00
Carter Li e3d6a85888 Display (Linux): detect scale factor for X11 2025-09-01 21:20:34 +08:00
李通洲 7d92da8829 Global (Android): enable X11 related stuff 2025-09-01 16:28:13 +08:00
李通洲 2f3a361b1f CMake: enable zlib on all platforms 2025-09-01 09:59:06 +08:00
李通洲 ac71f21e6c DisplayServer (Android): update WM name accurately
See #1933
2025-08-30 14:14:48 +08:00
李通洲 8d5316f6aa CMake (Android): link to libm
Fix #1939
2025-08-30 13:31:37 +08:00
Carter Li 1242fda66f Merge pull request #1938 from fastfetch-cli/dev
Release: v2.51.1
2025-08-29 14:05:34 +08:00
李通洲 5a2b618d27 Release: v2.51.1 2025-08-29 13:55:52 +08:00
李通洲 d836d7569f CPU (macOS): removes reliance on unavailable ARM capability headers on macOS
Fixes https://github.com/Homebrew/homebrew-core/pull/235425
2025-08-29 13:45:16 +08:00
Carter Li 8a412e6823 Packaging: update debian stuff [ci skip] 2025-08-29 08:56:30 +08:00
Carter Li 16b6aac764 Merge pull request #1933 from fastfetch-cli/dev
Release: v2.51.0
2025-08-29 08:43:08 +08:00
Carter Li 9f5046d69f CPU/GPU (Linux): Improves CPU/GPU temp detection accuracy on Linux/Android 2025-08-28 18:58:00 +08:00
李通洲 cace1a7156 Revert "Uptime (Windows): use QueryUnbiasedInterruptTime"
Fixes #1935

This reverts commit b812f3ccde.
2025-08-28 18:22:06 +08:00
李通洲 9c0cf863ba JsonSchema: update 2025-08-28 16:36:00 +08:00
Carter Li ffe55d9eee DisplayServer (Linux): upgrade kde-output-device-v2 2025-08-28 16:09:47 +08:00
李通洲 28bc9523d6 Release: v2.51.0 2025-08-28 14:40:31 +08:00
李通洲 ebf810ad4b GPU (Android): adds GPU temp detection support 2025-08-28 14:29:00 +08:00
Carter Li 5c9a0a1f88 Fastfetch: clarify that --debug is debug-mode only 2025-08-28 09:32:01 +08:00
李通洲 bc05a30724 CPU (Linux): improve temp detection
Support Android
2025-08-28 09:29:33 +08:00
李通洲 98c7803a24 Battery (Android): fix battery temp detection 2025-08-27 16:28:54 +08:00
李通洲 0893013e78 DisplayServer (Android): fix display server name 2025-08-27 15:43:50 +08:00
李通洲 e6985a8832 Global: handles missing config directories more gracefully 2025-08-27 15:29:38 +08:00
Carter Li 7a87638fec InitSystem (GNU): support shepherd detection 2025-08-27 14:46:20 +08:00
李通洲 00f163be32 CPU (Windows): detects march on WoA
Tested in VM
2025-08-27 09:22:02 +08:00
李通洲 68bbb2980e CPU (macOS): detects march on Apple Silicon 2025-08-27 09:22:02 +08:00
Carter Li dd1a799abb CPU (Linux): detects march on aarch64 2025-08-27 09:22:02 +08:00
Carter Li 7611d672b7 Merge pull request #1931 from CarterLi/dev
Add GNU/Hurd support
2025-08-25 13:41:53 +08:00
carter bfb93cd8f5 Processing (Linux): enhances robustness when extracting process name and related fields
... by accurately handling process names with spaces or special characters.
2025-08-25 10:39:56 +08:00
李通洲 0998b1e59e DiskIO (Linux): trim trailing white spaces 2025-08-25 09:26:04 +08:00
李通洲 588c4c0026 Chore: silense compiler warnings 2025-08-25 09:25:25 +08:00
Carter Li a80ea2b117 CPUUsage: adds user guidance when CPU time fails to increase 2025-08-24 22:23:07 +08:00
Carter Li 13110e3074 LocalIP (GNU): adds MAC addr detection support 2025-08-24 22:15:06 +08:00
Carter Li 0b2c0445c0 InitSystem: tidy 2025-08-24 22:09:22 +08:00
Carter Li 062963d6cc CMake (GNU): disable wifi support 2025-08-24 22:04:58 +08:00
Carter Li 4b7f231b5a Processing (GNU): fix command name reading 2025-08-24 21:52:38 +08:00
Carter Li 74e0732390 Common (GNU): more __GNU__ tests 2025-08-24 21:40:22 +08:00
Carter Li e9104c38c6 Terminal (GNU): enable version detection 2025-08-24 13:04:12 +01:00
Carter Li 4a7b3a8493 Processing (GNU): hurd uses cmdline instead of comm 2025-08-24 19:57:54 +08:00
Carter Li 20fafa5a21 WM (GNU): enable 2025-08-24 19:56:52 +08:00
Carter Li 1d32344cf7 Global (GNU): code cleanups 2025-08-24 19:37:06 +08:00
Carter Li 82a1eaf276 Chore: tidy tabs 2025-08-24 19:09:51 +08:00
Carter Li 75a023f4d7 CMake (GNU): enable a lot of things 2025-08-24 12:05:14 +01:00
Yelninei 53424300e3 localip: Remove AF_LINK on GNU.
https://salsa.debian.org/glibc-team/glibc/-/blob/sid/debian/patches/hurd-i386/submitted-AF_LINK.diff
2025-08-24 11:29:02 +01:00
Yelninei d553bc4893 WIP: shepherd initsystem 2025-08-24 11:29:01 +01:00
Yelninei add2bfd108 Fix localip_linux on GNU 2025-08-24 11:29:01 +01:00
Yelninei e508100a15 disable ffPackagesGetNix on when it is not defined 2025-08-24 11:29:01 +01:00
Yelninei 1a2f4b4c1f Port netif_gnu to the new api. 2025-08-24 11:29:01 +01:00
Yelninei e968bca89d Fork netif_linux to netif_gnu.
netif_linux now uses linux specifics which do not work on GNU.
2025-08-24 11:29:01 +01:00
Yelninei 71fbe04367 Start work on GNU 2025-08-24 11:29:01 +01:00
李通洲 f2f9b10b18 TerminalShell: remove special handling of hyfetch
Ref: https://github.com/search?q=repo%3Ahykilpikonna%2Fhyfetch%20FFTS_IGNORE_PARENT&type=code
2025-08-24 00:00:10 +08:00
李通洲 fae4892643 Fastfetch: improves config file generation message with tips 2025-08-23 20:37:29 +08:00
李通洲 8589bf2392 Chore: silence compiler warnings 2025-08-23 15:31:42 +08:00
李通洲 8b18e69980 CPU: fix building on non-x86 2025-08-23 15:28:48 +08:00
李通洲 9ae968fbd3 CPU: adds CPU microarchitecture detection for x64 and reporting
Fixes #1928
2025-08-23 15:17:57 +08:00
李通洲 8f6608db74 Disk: adds formatted free and available disk size fields
Fixes #1929
2025-08-23 13:59:48 +08:00
李通洲 45b6a333ec Logo (Builtin): adds AerynOS
Fixes #1926
2025-08-22 14:23:52 +08:00
李通洲 5012bc250b Processes (Linux): be compatible with Hurd 2025-08-22 14:08:18 +08:00
李通洲 5775409cb9 DisplayServer (Android): update WM name 2025-08-22 14:07:58 +08:00
李通洲 64da80d520 Fastfetch: improves format help output for config and variables
Fixes #1927
2025-08-21 23:57:37 +08:00
Carter Li 8b1bfcb34b WM (Linux): uses the same X11 props as neofetch to query WM name
Fixes twin detection
2025-08-21 18:35:09 +08:00
Carter Li 784a7a92c8 DE (Linux): adds Trinity version detection support 2025-08-21 18:19:23 +08:00
李通洲 8331242f42 GPU (BSD): fallbacks to pciids/pci.ids 2025-08-21 10:54:34 +08:00
李通洲 79fea61c90 Merge remote-tracking branch 'origin' into dev 2025-08-21 10:41:04 +08:00
Carter Li a8e7d38afd Packaging: update debian stuff [ci skip] 2025-08-21 10:39:59 +08:00
Carter Li 24467e8c46 GPU (BSD): always use pci.ids provided by hwdata
Fixes #1924
2025-08-21 09:23:01 +08:00
李通洲 6867b87c3e Disk: disable hyperlink by default and move it to custom keys 2025-08-21 08:53:51 +08:00
Carter Li cb13d43a7a TerminalShell (Linux): always ignore pid1 (v2) 2025-08-21 00:19:52 +08:00
Carter Li bd7190ca6d TerminalShell (Linux): always ignore pid1 2025-08-21 00:12:41 +08:00
Carter Li 49982588cf Disk (Linux): remove unused headers 2025-08-20 23:52:53 +08:00
Carter Li de2dff5da0 Common: corrects the position for appending milliseconds 2025-08-20 11:07:53 +08:00
Carter Li b05c54486f LocalIP (Linux): improves netlink route parsing by avoiding possible message truncation
Fixes #1919
2025-08-20 11:07:06 +08:00
Carter Li 1f1d7cf936 FFstrbuf: handles double rounding and zero representation in formatter 2025-08-20 10:10:30 +08:00
李通洲 26253f8863 GPU (Windows): improves GPU detection by refining device filtering 2025-08-19 19:03:55 +08:00
李通洲 08e6db090b Shell (Windows): be compatible with fish 4 built by MSYS2 2025-08-19 17:25:04 +08:00
李通洲 ec0fa89cc8 Common: refactors number formatting to use type-specific append functions 2025-08-19 17:22:11 +08:00
李通洲 7f48500cfd Format: replaces format specifiers with type-safe append functions 2025-08-19 16:04:00 +08:00
李通洲 a7eecf6fc7 FFstrbuf: improves double formatting precision handling 2025-08-19 16:03:04 +08:00
李通洲 8e282a3865 Duration: use ffStrbufAppendUInt 2025-08-19 15:19:12 +08:00
李通洲 dcbf76b233 FFstrbuf: adds number appending functions 2025-08-19 15:00:30 +08:00
李通洲 70b11d953c Logo (Builtin): honor logo.width 2025-08-19 10:35:11 +08:00
李通洲 fa3b634c07 JsonConfig: support JSON5 2025-08-19 10:25:52 +08:00
李通洲 ea86273a0e Common: refactors time formatting to use a shared buffer and utility macro 2025-08-19 09:49:43 +08:00
李通洲 4f88e1f26d 3rdparty: upgrade yyjson to 0.12.0 2025-08-19 08:43:38 +08:00
李通洲 805e277429 JsonConfig: adds 'succeeded' module condition to JSON config
Fixes #1908
2025-08-18 14:18:37 +08:00
李通洲 3ce3de2963 OS: set the icon of unknown OS type as a cog 2025-08-18 14:03:52 +08:00
李通洲 3b5e9c74d6 Modules: return bool to indicate whether the detection is succeeded 2025-08-18 13:38:30 +08:00
李通洲 a9aaa36b2c CI (DFBSD): enable 2025-08-17 23:08:43 +08:00
李通洲 bef4ee1fbc CI (SunOS): fix build 2025-08-17 23:03:45 +08:00
李通洲 b3ddd084ba Merge remote-tracking branch 'upstream/master' into dev 2025-08-17 23:03:17 +08:00
Mathias Korsbäck fef3b7c647 CPU (macOS): changes CPU to M2 Pro for Mac14,12 host (#1915)
Currently states it's a M2 but according to https://support.apple.com/en-us/102852 and https://everymac.com/ultimate-mac-lookup/?search_keywords=Mac14%2C12 it's a M2 Pro.
2025-08-17 21:37:17 +08:00
Carter Li 4dfba31cae Merge pull request #1911 from fastfetch-cli/dev
Release: v2.50.2
2025-08-16 21:50:39 +08:00
Carter Li 3004f29c08 Release: v2.50.2 2025-08-16 21:18:07 +08:00
李通洲 b994ce5b55 LocalIP: refines default route detection and JSON output for local IPs
Add verbose log for Windows
2025-08-16 18:27:30 +08:00
李通洲 6356f9d0e5 Netif (Linux): improves default route detection and error handling
Ref: #1902
2025-08-16 17:15:44 +08:00
李通洲 597c6f3dbc Netif (Linux): add verbose logs 2025-08-16 15:13:07 +08:00
李通洲 41cffac80c CI: adds default build type to CI environment 2025-08-16 13:10:35 +08:00
李通洲 c4cb6c65a9 LocalIP (Linux): add verbose debug log 2025-08-16 04:43:28 +00:00
李通洲 46081a3e52 LocalIP (Linux): fixes incorrect return and ensures struct initialization 2025-08-16 04:24:26 +00:00
李通洲 a5fd671b92 LocalIP: fix showMac does not honor defaultRouteOnly 2025-08-15 20:20:43 +08:00
李通洲 8319512c83 Merge remote-tracking branch 'origin' into dev 2025-08-15 08:58:15 +08:00
Ashish SHUKLA c1db692982 FFstrbuf: wrap yyjson.h include in conditional 2025-08-15 08:49:53 +08:00
Guiling Qiyu aec2bfd2a4 Packages (Linux): fixes Linglong detection by counting linglong layers (#1903)
* Packages (Linux): fixes Linglong detection on Deepin

* Packages (Linux): fixes Linglong detection to count layers

* Update src/detection/packages/packages_linux.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-08-14 19:47:20 -05:00
Carter Li 7bacf20f72 Merge pull request #1901 from fastfetch-cli/dev
Release: v2.50.1
2025-08-14 22:35:06 +08:00
Carter Li 1479de19ef Release: v2.50.1 2025-08-14 18:34:30 +08:00
Guiling Qiyu bb9ca73db1 Packages (Linux): fixes Linglong detection on Debian (#1899)
Fixes #1898
2025-08-14 18:06:42 +08:00
李通洲 81bac8bca4 Percent: refactors bar color logic for clarity and consistency; update examples 2025-08-14 16:47:30 +08:00
李通洲 56d22292b0 Revert "Percent: fix a copy-paste error"
This reverts commit 3345c1e9dd.
2025-08-14 16:04:55 +08:00
李通洲 9a11ff8ddb Packages (Android): fix building 2025-08-14 14:42:09 +08:00
Carter Li a99b6d602d Merge pull request #1897 from fastfetch-cli/dev
Release: v2.50.0
2025-08-14 14:24:33 +08:00
李通洲 40921156b8 Doc: update changelog [ci skip] 2025-08-14 14:23:37 +08:00
李通洲 bc3703140b Doc: update changelog 2025-08-14 13:58:21 +08:00
李通洲 bd5b385909 Flashfetch: disable decimal digits in Disk module 2025-08-14 13:32:21 +08:00
李通洲 0fe3db419e Separator: honors FQDN settings in Title module 2025-08-14 13:30:02 +08:00
李通洲 e80bb480c4 Doc: update changelog 2025-08-14 11:03:26 +08:00
李通洲 d4773212b7 Fastfetch: adds support for reading JSON config from stdin 2025-08-14 11:00:35 +08:00
李通洲 9ebff9fd22 Chore: removes undocumented flag --load-config 2025-08-14 10:43:22 +08:00
李通洲 5d8edc0c8b Doc: update changelog [ci skip] 2025-08-14 10:27:02 +08:00
李通洲 78530b4e34 Release: v2.50.0 2025-08-14 10:20:05 +08:00
李通洲 61f2823903 Global: fixes -ffast-math compatibility
Unifies unset double handling using `-DBL_MAX` sentinel

Fixes #1894
2025-08-14 10:01:34 +08:00
李通洲 7446828866 GPU (macOS): don't set platformApi to Metal when Metal API is not used 2025-08-14 08:34:56 +08:00
李通洲 0b37acec5b GPU (Windows): ignore software adapters; add verbose logs 2025-08-14 01:07:39 +08:00
李通洲 53ecf57f19 Doc: update changelog [ci skip] 2025-08-13 10:08:25 +08:00
李通洲 e1c4365c10 Cursor (macOS): improves color detection and rounding for cursor info 2025-08-13 09:28:25 +08:00
NEOAPPS ebc60ac66c Logo (Builtin): add ObsidianOS (#1890) 2025-08-12 21:32:38 +08:00
李通洲 4004501d0f Packages: unifies Nix package detection code
Fixes: #1893
2025-08-12 19:37:52 +08:00
李通洲 a0265c3204 CI: upgrade to actions/checkout@v5 2025-08-12 09:20:04 +08:00
Osama Albahrani 3ef84834fc README: HomeBrew -> Homebrew (#1891) [ci skip]
See https://brew.sh
2025-08-11 20:08:11 -05:00
李通洲 3276949663 Doc: update README & Changelog 2025-08-11 16:42:53 +08:00
李通洲 1ec69d6838 OS (Linux): tidy 2025-08-11 16:38:39 +08:00
李通洲 7f1063d09b Revert "CPU (macOS): use CPUID for freq detection on Intel"
This reverts commit 7ee0e8726e.
2025-08-11 16:35:35 +08:00
李通洲 883923de4a CI (Haiku): reduce errors when installing deps (hopefully) 2025-08-11 15:27:20 +08:00
李通洲 146981009b CommandLine: add --gen-config-full 2025-08-11 14:49:22 +08:00
李通洲 060b69293c Presets: add an example
Fix #1887
2025-08-11 14:19:09 +08:00
李通洲 3345c1e9dd Percent: fix a copy-paste error 2025-08-11 14:18:41 +08:00
李通洲 1c8e2e34ba JsonSchema: remove unused properties [ci skip] 2025-08-11 14:16:13 +08:00
李通洲 5ab51c07d1 Doc: don't recommand Ubuntu PPA [ci skip] 2025-08-11 09:58:44 +08:00
Juanma eee98e54d0 OS (Linux): fix lliurex detection (#1882)
* Proper detection of lliurex distribution

* fix newline

* Trim version and not versionID as assigned to lliurex-version  output

* Update os_linux.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-08-10 20:45:53 -05:00
Carter Li b0340d5581 DisplayServer: merge serverVender into wmProtocolName
Fix #1888
2025-08-11 09:16:05 +08:00
aequabit 1124342eda Display (Linux): show brand of Xserver in WM section (#1888)
* Display: add server vendor string

* Display (X11): fetch server vendor string using XCB/Xlib

* WM: show server vendor string when not empty

* Display (XCB): use proper string helper function

* Display (X11): shorten "The X.Org Foundation" to "Xorg"
2025-08-11 09:03:23 +08:00
李通洲 329cb229f8 Chore: remove unused functions 2025-08-10 23:15:13 +08:00
李通洲 bedb5eb6c5 Netif (SunOS): work around a bug that fails to detect default route for IPv4 2025-08-10 21:42:01 +08:00
李通洲 f184f8dab5 GPU (FreeBSD): fix gpu driver detection when DRM is used 2025-08-10 08:48:00 +08:00
Carter Li 7ee0e8726e CPU (macOS): use CPUID for freq detection on Intel 2025-08-10 00:14:16 +08:00
Carter Li a7347130de LocalIP (Linux): fix building 2025-08-09 22:20:04 +08:00
Carter Li f3c82ad837 LocalIP (SunOS): add speed detection support 2025-08-09 19:53:31 +08:00
Carter Li 1bde2b31f9 LocalIP (SunOS): support isIPv6AddressPreferred 2025-08-09 19:27:07 +08:00
Carter Li 1edc617b55 LocalIP (SunOS): add more if flags 2025-08-09 19:19:50 +08:00
李通洲 2bb451d9e4 LocalIP (Linux): fix compiler warnings 2025-08-09 18:44:37 +08:00
李通洲 4588644d39 Networking (SunOS): fix compiler warnings 2025-08-09 18:35:53 +08:00
李通洲 ed94b4c46c Netif (SunOS): fix compiler warnings 2025-08-09 18:34:25 +08:00
Carter Li f96ddb4c10 LocalIP (BSD): fix compiling 2025-08-08 15:32:12 +08:00
李通洲 1b0a65ecf2 Wifi: updates default WiFi percentage thresholds 2025-08-08 14:59:39 +08:00
李通洲 33983c5402 LocalIP: improve preferred IPv6 address detection 2025-08-08 14:40:04 +08:00
李通洲 8cfee9d693 Netif: unifies BSD netif handling 2025-08-08 11:03:04 +08:00
Carter Li 64568b31d1 Netif (Haiku): add preferred source addr 2025-08-08 10:03:43 +08:00
李通洲 02c999725c NetIO (SunOS): fix build 2025-08-07 23:30:53 +08:00
李通洲 be11013ae2 LocalIP (BSD): fix building 2025-08-07 23:28:54 +08:00
Carter Li a84c4dc1f4 Netif: refactor API for dual-stack route detection
Unifies IPv4 and IPv6 default route queries under a shared result structure and per-family functions. Improves clarity and extensibility by centralizing route logic, streamlining detection of preferred interfaces, and updating all consumers to use the new API.

Prepares for more robust multi-protocol network information handling.
2025-08-07 16:35:42 +08:00
李通洲 d9455adc7f Display: fix invalid size.maxPrefix default value in generated config file 2025-08-06 21:57:21 +08:00
李通洲 b20aea7ab8 Netif (BSD): split different implementations 2025-08-06 13:58:41 +08:00
Jannis Pohl 5e770dc8b0 LocalIP: consider preferred source address when retrieving default route (#1883)
* LocalIP: consider preferred source address when retrieving default route

* LocalIP: fix logic error when there is no preferred source address

* LocalIP: use macros rather than manual free/close

* LocalIP(BSD): fix build error

* LocalIP: address Copilot suggestions
2025-08-05 23:30:06 +08:00
李通洲 137d5dfe90 LocalIP (Windows): show only preferred IP when showAllIPs is not set
Ref: #1883
2025-08-05 19:35:54 +08:00
李通洲 655d11c1cc Chore: fix building on Windows 2025-08-05 19:15:52 +08:00
李通洲 e32987c408 JsonConfig: make all non-module keys case-sensitive 2025-08-05 16:47:48 +08:00
李通洲 fa4e11c73b JsonConfig: write all flags when generating config file 2025-08-05 16:47:48 +08:00
李通洲 e753d4d3a4 Doc: remove command line flags of modules 2025-08-04 15:08:30 +08:00
李通洲 75d2c668d0 Modules: refactor module option handling for static allocation
Moves module option structs out of global config and removes dynamic allocation, using static buffers and size assertions for safer, simpler management.

Refactors module initialization and destruction to work with isolated option structs, eliminating the need for the previous modules container and related code.

Unifies module option header usage and updates detection logic to leverage statically-sized option buffers, improving encapsulation and maintainability.

Simplifies module function signatures and reduces coupling between modules and config.

Enhances future extensibility and reliability by enforcing max size constraints and removing unnecessary indirections.
2025-08-04 14:46:01 +08:00
李通洲 559082806b Modules: export module info 2025-08-04 00:06:28 +08:00
李通洲 6f8d276545 Modules: add init and destroy option callbacks to module info 2025-08-03 18:40:53 +08:00
李通洲 582268f44f Disk (Linux): ignore Bedrock Linux subvolumes
Ref: https://github.com/fastfetch-cli/fastfetch/issues/1881#issuecomment-3148302531
2025-08-03 18:19:45 +08:00
李通洲 9b68674c4f OS (Linux): don't detect Bedrock linux when ran restricted
Fix #1881
2025-08-03 18:18:12 +08:00
李通洲 badae2ba9d JsonSchema: Improves JSON schema enums with oneOf objects containing descriptive explanations for allowed values 2025-08-03 10:22:32 +08:00
李通洲 dd4f006b5f GPU: support "hideType": null 2025-08-03 10:22:32 +08:00
李通洲 c491c9e8fc Display: add compactMode: null; improve json schema 2025-08-03 10:22:32 +08:00
李通洲 094d736d38 Modules: remove all parseCommandOptions and related stuff 2025-08-03 10:22:32 +08:00
李通洲 22bfaf3c69 JsonSchema: small improvements 2025-08-03 10:22:32 +08:00
李通洲 980e552eba Display: allow "compactType": null; improve json schema 2025-08-03 10:22:32 +08:00
李通洲 4a141c3f57 Disk: add missing JSON config options 2025-08-03 10:22:32 +08:00
Carter Li 59289bef6c Percent: silense compiler warnings 2025-08-02 19:03:42 +08:00
李通洲 0b02543ef2 JsonConfig: refactor JSON key handling to improve safety and consistency
Also make keys case-sensitive
2025-08-02 18:51:03 +08:00
李通洲 3cef51ec4a JsonConfig: refactor string buffer JSON handling for robustness 2025-08-02 17:41:19 +08:00
李通洲 6d86813647 Doc: update changelog; fix typo 2025-08-01 16:36:32 +08:00
李通洲 fb267acac3 Presets: add new config; fix old config 2025-08-01 16:06:03 +08:00
李通洲 ba3e26f2b4 Option: fix a possible null reference segfault 2025-08-01 16:05:18 +08:00
李通洲 4f8d8de749 Doc: update changelog [ci skip] 2025-08-01 15:39:19 +08:00
李通洲 54c5bc5110 Bar: refactor config to use nested objects and deprecates old fields 2025-08-01 15:12:30 +08:00
李通洲 c6675f82f0 Bar: add customizable bar color options for percentage bars 2025-08-01 15:03:24 +08:00
李通洲 afe2c85047 Bar: add configurable elapsed bar borders for percent bars
Fix #1875
2025-08-01 15:03:24 +08:00
李通洲 671b11157e Wifi (macOS): disable using of ipconfig on 15.6 too
Ref: #1874
2025-08-01 08:54:31 +08:00
李通洲 78fb55c35c Chore: remove sensitive data [ci skip] 2025-07-31 18:58:57 +08:00
李通洲 559905da60 Changelog: fix typo [ci skip] 2025-07-31 14:54:53 +08:00
Carter Li e093c8aa72 Packaging: update debian stuff [ci skip] 2025-07-31 14:34:18 +08:00
Carter Li ba8a21142f Merge pull request #1873 from fastfetch-cli/dev
Release: v2.49.0
2025-07-31 13:54:49 +08:00
李通洲 eca3625165 Battery / Uptime: update document of custom format 2025-07-31 13:32:18 +08:00
李通洲 677e920dc8 Battery: address copilot feedback 2025-07-31 10:51:53 +08:00
李通洲 38c0b24daa WM (Linux): fix a copy-paste error. 2025-07-31 10:50:45 +08:00
李通洲 4e05502d7a Release: v2.49.0 2025-07-31 10:42:09 +08:00
李通洲 d0928a63bf Doc: update readme 2025-07-30 16:18:04 +08:00
李通洲 aa0bbd5aee Percent: add option --percent-width 2025-07-30 15:06:16 +08:00
李通洲 ce554dbdd0 Uptime / Battery: add formatted duration string in custom format 2025-07-30 15:03:23 +08:00
李通洲 a0174e8666 Global: add new unit related options
1. `--<module>-space-before-unit`
2. `--duration-abbreviation`
3. various code refactoring and cleanups
2025-07-30 15:03:23 +08:00
李通洲 8be419cfd6 DiskIO: fix wrong /s assignment in custom format
Fix #1871
2025-07-30 09:05:33 +08:00
李通洲 ca79bae36e Packages (Windows): find scoop installation path by parsing scoop config file 2025-07-29 19:29:40 +08:00
Carter Li b1f0248fb3 Font (Linux): parse unicode escaped string stored by qt5ct
Fix #1864
2025-07-29 18:25:34 +08:00
Carter Li 77dd18466b FFstrbuf: add function ffStrbufAppendUtf32CodePoint 2025-07-29 16:36:21 +08:00
李通洲 5bb6e22679 GPU (Intel): read render engine temperature only 2025-07-29 14:23:56 +08:00
Carter Li 9ea9291ab8 WM (Linux): add labwc version detection support 2025-07-29 10:20:05 +08:00
Carter Li 6ec73863ab CPU (Android): make SOC detection more loose
It's less accurate, but higher chance to match.
2025-07-29 09:28:41 +08:00
Carter Li 8c2f93151d CPU (Android): add more QSD SOCs 2025-07-29 09:28:36 +08:00
李通洲 71ddc4ffc6 Disk: update default value of hideFolders
Fix #1869
2025-07-28 23:49:27 +08:00
李通洲 4909d693e3 Packages (Windows): don't rely on the existance of $SCOOP when detecting scoop packages
Fix #1868
2025-07-28 23:41:48 +08:00
李通洲 fe76bbe68a Logo (Builtin): remove Evolinx 2025-07-28 23:06:15 +08:00
李通洲 d1f20822f1 GPU (macOS): silence compiler warnings 2025-07-28 15:39:35 +08:00
李通洲 1ed804db52 Wifi (macOS): use sudo wdutil info on Tahoe
sudo, you know it.
2025-07-28 15:35:02 +08:00
李通洲 0e8b9bec2d FFstrbuf: add function ffStrbufSubstr 2025-07-28 15:35:02 +08:00
李通洲 a3182c31cb Chore: add FF_C_NONNULL 2025-07-28 15:35:02 +08:00
Darloli d2f2c76dfc Version: correct the variable name 'name' to 'project-name' 2025-07-26 08:33:34 +08:00
Darloli 2d1ae1b4c5 Users: correct the variable name 'session' to 'session-name' 2025-07-26 08:33:34 +08:00
李通洲 316409ecc3 LocalIP: cleanup printing code 2025-07-24 20:12:48 +08:00
李通洲 f0fc38bcb5 LocalIP (Windows): fix link speed calcuation 2025-07-24 20:11:04 +08:00
李通洲 e7a6b84107 LocalIP (Windows): ignore stopped interfaces 2025-07-24 19:31:41 +08:00
李通洲 02c3254961 Netif (Windows): correct default route detection (v2) 2025-07-24 19:31:41 +08:00
李通洲 a90e1d7ccf JsonSchema: improve definitions of colors and conditions [ci skip]
Fix #1862
2025-07-23 09:31:25 +08:00
Carter Li 6cdd64ac55 CI (Haiku): remove work around 2025-07-22 22:10:00 +08:00
Carter Li aa1201ffb8 Editor: correct the variable name full-path to path
Fix #1861
2025-07-22 22:06:26 +08:00
Carter Li 9b491c2f49 Wifi (Linux): fix interface status when the interface is up but not connected 2025-07-22 22:03:53 +08:00
李通洲 be3e2ba521 Presets: improve 25.jsonc; add verbose comments [ci skip] 2025-07-22 15:46:36 +08:00
李通洲 ccbb9e90ea Netif (Windows): fix default route detection when the default adapter is disabled
This commit addresses an issue where the default route detection on Windows incorrectly identified a disabled adapter as the default route. Previously, when a user disabled the adapter configured as the default route, the system still reported it as active due to stale routing table entries.
2025-07-21 20:24:43 +08:00
李通洲 d07fe997a9 CI (NetBSD): remove opencl support to fix building 2025-07-21 14:41:02 +08:00
李通洲 b60996bcd1 Packages (Linux): remove qi support
Close #1858
2025-07-21 14:19:12 +08:00
李通洲 272c0aad9c Packages (Linux): improve accuracy of flatpak count detection
Fix #1856
2025-07-21 14:06:19 +08:00
Carter Li 7566f10bb6 Logo (Builtin): add Aeon
Fix  #1855
2025-07-20 16:47:35 +08:00
Carter Li 847b76b863 GPU (Linux): add GPU temp detection for nouveau driver 2025-07-19 18:17:28 +08:00
Carter Li 5c0ad030cc GPU (Linux): support advanced detection for nouveau driver 2025-07-19 16:47:42 +08:00
Carter Li 02aafbd7f4 Merge pull request #1852 from fastfetch-cli/dev
Release: v2.48.1
2025-07-18 19:28:54 +08:00
Carter Li 72da8150bd Release: v2.48.1 2025-07-18 18:50:30 +08:00
Carter Li aca2b5336d WM (Linux): fix a copy-paste error 2025-07-18 18:04:00 +08:00
李通洲 c79b67efc1 Modules: don't report errors when condition key is set 2025-07-18 16:16:38 +08:00
李通洲 30af91ce8e Packages: add new option --packages-combined 2025-07-18 15:55:33 +08:00
李通洲 6c56348e54 JsonConfig: add modules[n].condition to run modules conditionally on different platforms 2025-07-18 15:45:25 +08:00
李通洲 531b25dc2f Version: replace WIN32 with Windows and Darwin with macOS 2025-07-18 15:08:40 +08:00
李通洲 8c6dc34654 Processing (*nix): fix compiling on Android 7 2025-07-18 13:27:17 +08:00
李通洲 cf2034b93e Processing (Windows): redirect unused std handles to NUL to avoid potential errors 2025-07-18 10:39:11 +08:00
李通洲 f7db03b8c4 Processing (*nix): use traditional fork-exec on Android and OpenBSD
Fix https://github.com/termux/termux-packages/issues/25369
2025-07-18 10:37:52 +08:00
Carter Li 8647e366f9 Packaging: update debian stuff [ci skip] 2025-07-17 16:27:07 +08:00
李通洲 1bf41d68f9 WM (Linux): add Openbox version detection 2025-07-17 14:15:35 +08:00
Carter Li 1ac1f1f889 Chore: silense compiler warnings 2025-07-16 15:19:48 +08:00
Carter Li 14f1278485 Release: v2.48.0 (#1848)
Co-authored-by: Dariqq <77271900+Dariqq@users.noreply.github.com>
Co-authored-by: Robert Nilson <109800336+ZBookCMD@users.noreply.github.com>
Co-authored-by: Juan Llamas <38849891+xoltia@users.noreply.github.com>
Co-authored-by: Angel Gustavo Lopez <143856402+Xray-OS@users.noreply.github.com>
2025-07-16 15:09:29 +08:00
李通洲 c2c6856159 Doc: optimize README; fix typo 2025-07-16 14:45:56 +08:00
李通洲 c89f3d2896 Release: v2.48.0 2025-07-16 14:33:22 +08:00
李通洲 8e773470df Logo: partially revert c5c0e54 2025-07-16 14:29:41 +08:00
李通洲 ea4fc7bdda Separator: remove formatArgs
It makes no sense.
2025-07-16 10:46:47 +08:00
李通洲 468d1e0903 Display: add option --fraction-ndigits
to control number of digits to print when formatting ordinary fraction numbers
2025-07-16 10:33:20 +08:00
李通洲 6851e7b082 Uptime / Users: add years, days-of-year and year-fraction
Like what `Disk` has
2025-07-16 09:53:09 +08:00
Carter Li a734f18fd5 Chore (Linux): silience compiler warnings 2025-07-15 23:33:26 +08:00
李通洲 30b1e29785 JsonSchema: update xxxFormat [ci skip] 2025-07-15 22:44:56 +08:00
李通洲 dde0c22195 Disk: add keys years, days-of-year and years-fraction
Fix #1847
2025-07-15 22:38:31 +08:00
Angel Gustavo Lopez 1311a809db Logo (Builtin): rename ada to xray_os (#1845)
* going back to xray_os

* going back to xray_os

---------

Co-authored-by: xray_os <xray_os>
2025-07-15 17:52:09 +08:00
李通洲 60a54f4880 CMake: reconfigure after adding / removing logos 2025-07-15 11:02:31 +08:00
李通洲 b4e65e7e48 README: document how to run multiple modules on command line [ci skip] 2025-07-15 10:48:37 +08:00
李通洲 6f3ed4a7b4 Processing (Linux): cache the index of $LANG 2025-07-15 10:22:56 +08:00
李通洲 cc8f8ff0f7 README: add DeepWiki badge [ci skip]
An interesting website
2025-07-15 08:51:15 +08:00
李通洲 8a00f2d901 GPU (Windows): fix compiling on x86-32 2025-07-15 00:04:43 +08:00
李通洲 c5c0e543e4 Logo: don't print builtin logo if the provided logo source cannot be found 2025-07-13 20:32:31 +08:00
李通洲 97255f37da Logo: load .raw files as raw image file 2025-07-13 20:32:31 +08:00
李通洲 fb8a04f97a Logo: don't load text files as image file
Fix #1843
2025-07-13 20:32:13 +08:00
李通洲 c3ce5ac947 Logo: don't parse file paths as builtin logo name 2025-07-13 20:15:10 +08:00
李通洲 eae69049b2 GPU (Windows): more method to detect device name 2025-07-13 01:39:38 +08:00
李通洲 102e8fcc72 GPU (Windows): detect GPU frequency by default
Supported on Windows 11 only
2025-07-13 01:16:46 +08:00
李通洲 8372708f98 GPU (Intel): prefer matching GPU with bus id 2025-07-13 01:16:46 +08:00
Juan Llamas 5011edc9d9 Packages (Linux): clean up nix user package detection 2025-07-12 23:57:51 +08:00
Juan Llamas 94a5228ffc Packages (Linux): add /etc/profiles/per-user detection for nix user packages 2025-07-12 23:57:51 +08:00
李通洲 382c0cd7c3 GPU (Windows): ignore invalid temps 2025-07-12 15:16:36 +08:00
李通洲 ab496b23b7 GPU (Windows): greatly improve performance of GPU temp detection
... when `--gpu-driver-specific` is not set. Supported on Windows 10 and later
2025-07-12 01:26:33 +08:00
李通洲 939f428da7 Logo (Builtin): add AxOS
Fix #1841
2025-07-11 14:01:30 +08:00
Robert Nilson 2d496c91e1 Logo (Builtin): add the Minimal System logo (#1837)
* Added logo of Minimal System

* Changed to spaces instead of tabs

* Removed paddings for minimal.txt

* Changed

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-07-10 03:31:49 -05:00
李通洲 442d58b646 Revert "GPU (macOS): update how integrated GPUs are detected"
This reverts commit 5381395c54.
2025-07-10 16:16:45 +08:00
李通洲 4d377b94b7 CI (Haiku): Apply work-around for work directory
From <cross-platform-actions/action#104 (comment)>
2025-07-10 14:40:25 +08:00
李通洲 7248868e33 Sound (macOS): improve device id detection 2025-07-10 10:42:23 +08:00
Carter Li 2eda6464ad Processing (Linux): use posix_spawnp for better performance 2025-07-09 23:56:02 +08:00
Carter Li 2622fc12a6 Chore (Linux): silence compiler warnings 2025-07-09 20:23:28 +08:00
李通洲 b178e43428 GPU (Windows): use nvapi to detect GPU type 2025-07-09 00:28:16 +08:00
李通洲 d00fca26c5 GPU (Windows): clean up 2025-07-09 00:08:13 +08:00
李通洲 23e4d1c4aa Chore (Windows): tidy 2025-07-07 22:34:23 +08:00
李通洲 6871c8bb73 GPU (Windows): fix Win7 compatibility 2025-07-07 22:34:04 +08:00
李通洲 61adc7cf64 GPU (Windows): new method to detect device type 2025-07-07 22:03:30 +08:00
李通洲 9ba30adcba GPU (Windows): add driver version fall back 2025-07-06 18:23:14 +08:00
李通洲 010b2c6262 CMake (Windows): remove setupapi dependency 2025-07-06 17:48:39 +08:00
李通洲 c65fb1a868 Battery (Windows): use CMAPI instead of SetupAPI 2025-07-06 17:04:51 +08:00
李通洲 2029679ea5 GPU (Windows): use CMAPI instead of SetupAPI
Improve performance
2025-07-06 17:04:31 +08:00
Carter Li 817f70c2cd Presets: add a new example
Fix #1832
2025-07-05 08:33:55 +08:00
Carter Li 3a1f0485f4 PhysicalDisk: unifying white space trimming 2025-07-05 08:31:21 +08:00
李通洲 64910d0781 OS (Linux): detect fedora variants
Fix #1830
2025-07-04 10:31:59 +08:00
Dariqq 821462e152 Chore: Add a missing semicolon (#1828)
Followup to a9f021ccb9
2025-07-03 20:16:14 -05:00
Carter Li b015fd579c Packaging: update debian stuff [ci skip] 2025-07-03 14:53:14 +08:00
Carter Li 8b40a81e22 Merge pull request #1826 from fastfetch-cli/dev
Release: v2.47.0
2025-07-03 14:05:23 +08:00
李通洲 8be64714ba OS (Linux): remove duplicated code 2025-07-03 11:03:14 +08:00
李通洲 fe5d739cba Doc: update README [ci skip] 2025-07-03 10:51:42 +08:00
李通洲 dba0672a11 CMake: remove the unused option ENABLE_CPUUSAGE_PERFLIB 2025-07-03 10:47:44 +08:00
李通洲 3ed6acf3ca Release: v2.47.0 2025-07-03 10:45:41 +08:00
李通洲 8c74c54bb0 README 2025-07-03 10:27:44 +08:00
Carter Li 818473102c Logo (Builtin): always use FG_DEFAULT on title and keys 2025-07-03 09:39:32 +08:00
Carter Li f1cc4a7805 Logo (Builtin): fix colors of raw Linux logo 2025-07-03 09:36:39 +08:00
Carter Li c574af97a4 Logo (Builtin): fix colors of DragonFly 2025-07-03 09:33:04 +08:00
Carter Li 74ae84e719 Revert "Logo (Builtin): :%s/FG_WHITE/FG_DEFAULT/g"
This reverts commit bdbc885811.
2025-07-03 09:03:23 +08:00
李通洲 98738b6920 CPUUsage (Windows): detect perflib support dynamically based on OS version 2025-07-02 19:40:22 +08:00
李通洲 2e5769def2 OS (Linux): add support of Xubuntu
Fix #1825
2025-07-02 09:41:07 +08:00
李通洲 18a6929662 CPUUsage (Windows): disable ENABLE_CPUUSAGE_PERFLIB by default
Because Windows 7 doesn't support it
2025-07-01 22:08:08 +08:00
李通洲 0e61d1134d CMake: fix typo 2025-07-01 21:05:37 +08:00
李通洲 4abb183735 CPUUsage(Windows): add new method using Windows Performance Library 2025-07-01 20:53:46 +08:00
李通洲 d5b56be4ff CMake (SunOS): drop pciaccess dependency 2025-07-01 20:32:45 +08:00
李通洲 1854953d8c Chore (Windows): move perflib_.h to somewhere global 2025-07-01 14:57:40 +08:00
李通洲 2406015c81 Terminal (Linux): ignore init and systemd 2025-06-30 19:41:59 +08:00
李通洲 ec7f14ab96 CpuUsage (Windows): refine KernelTime calculation by removing unused DPC and interrupt time 2025-06-30 19:37:04 +08:00
李通洲 d94cdf4424 CpuUsage (Linux / BSD): include interrupt and softirq times in CPU usage calculations 2025-06-30 19:36:46 +08:00
李通洲 40e57b7698 IO: increase PROC_FILE_BUFFSIZ to avoid possible short reads 2025-06-30 19:16:08 +08:00
李通洲 974c658fff README: add the OpenBSD and DragonFly installation method [ci skip]
Fix https://github.com/fastfetch-cli/fastfetch/issues/1819#issuecomment-3015070008
2025-06-28 23:39:01 +08:00
李通洲 ad0ddfd7f1 Media (macOS): support old macOS version 2025-06-27 16:00:27 +08:00
李通洲 1da8367f55 Media (macOS): simplify now playing handling
Also improve performance
2025-06-27 14:28:45 +08:00
李通洲 bdbc885811 Logo (Builtin): :%s/FG_WHITE/FG_DEFAULT/g
To improve visibility on white background
2025-06-26 22:36:15 +08:00
李通洲 86e5a5997b Display (FreeBSD): silence a compiler warning 2025-06-26 21:44:06 +08:00
李通洲 9832a0e45b GPU (FreeBSD): fix compiling when libdrm is not available
Fix #1820
2025-06-26 21:34:34 +08:00
李通洲 addf674621 OS (Linux): append version string for Ubuntu variants 2025-06-26 21:31:16 +08:00
李通洲 863c5583ef GPU (OpenBSD): fix pci.ids file location
Fix #1819

Signed-off-by: kevlo <kevlo@openbsd.org>
2025-06-25 13:45:49 +08:00
李通洲 45cbc6de83 OS (macOS): force reporting 26 on macOS Tahoe
Fix #1809
2025-06-25 09:19:08 +08:00
李通洲 e68f766b4d OS (Linux): improve RPIOS detection
Ref: https://github.com/fastfetch-cli/fastfetch/issues/1816#issuecomment-2996316164
2025-06-23 22:10:50 +08:00
李通洲 29d7a1acac OS (Linux): use ffStrbufSetStatic where applicatable 2025-06-23 19:41:57 +08:00
李通洲 8d59d14b80 OS (Linux): clean up dietpi related code 2025-06-23 19:41:31 +08:00
Carter Li ed1883909a OS (Linux): detect DietPi
Fix #1816
2025-06-23 18:30:04 +08:00
李通洲 049701a8a9 CI (FreeBSD): run with 14.3 2025-06-23 16:13:40 +08:00
Carter Li 13b7bc89eb Sound (SunOS): rework; drop pulseaudio dependency 2025-06-22 20:35:29 +08:00
Carter Li 92fe44183d Shell (SunOS): ignore leading - 2025-06-22 12:12:49 +08:00
Carter Li 8ebc980c17 GPU (SunOS): simplify 2025-06-22 11:20:19 +08:00
Carter Li dbeb338bda PhysicalDisk (SunOS): rework; support more device types 2025-06-22 11:14:29 +08:00
Carter Li 65ff11a8d0 PhysicalDisk (SunOS): add support 2025-06-22 01:16:50 +08:00
Carter Li 7a73211484 Logo (Builtin): use FG_DEFAULT instead of FG_WHITE 2025-06-21 23:51:40 +08:00
Carter Li ca049997b1 GPU (SunOS): rework GPU detection 2025-06-21 23:22:37 +08:00
李通洲 a9f021ccb9 Chore: remove useless semicolons 2025-06-21 20:46:51 +08:00
Carter Li 55249c2294 BIOS (SunOS): detect BIOS type 2025-06-21 20:46:51 +08:00
李通洲 c13da56959 OS (macOS): remove useless code 2025-06-20 19:28:03 +08:00
Carter Li 665c7cd5d3 Packaging: update debian stuff [ci skip] 2025-06-20 15:02:23 +08:00
Carter Li 469e21cce9 Merge pull request #1813 from fastfetch-cli/dev
Release: v2.46.0
2025-06-20 14:30:06 +08:00
李通洲 925e09c88a Doc: update changelog [ci skip] 2025-06-20 14:28:33 +08:00
李通洲 488454c1aa Logo (Builtin): simplify kali linux 2025-06-20 14:19:05 +08:00
李通洲 c67c52d606 Logo (Builtin): add Kalpa Desktop
Fix #1807
2025-06-20 14:18:21 +08:00
李通洲 e4e11ee509 Release: v2.46.0 2025-06-20 09:51:54 +08:00
李通洲 a3e2592555 Doc: update help.json 2025-06-20 09:51:40 +08:00
Carter Li e0e966dadf Logo (Builtin): rename hydra framework to hydrapwk
Fix #1812
2025-06-20 08:59:53 +08:00
李通洲 b079a8643b Chore: code cleanups 2025-06-19 22:41:30 +08:00
apocelipes 3291a9945f Global: add missing O_CLOEXEC to open() 2025-06-19 22:40:06 +08:00
李通洲 68fd21d0e4 GPU (Linux): fix an issue which vram_usage is bigger t han vram_visible 2025-06-19 22:00:48 +08:00
李通洲 0e1ef96992 GPU (Linux): detect shared vram usage of AMD GPU 2025-06-19 15:54:26 +08:00
李通洲 c377872438 GPU (Linux): correctly call radeon driver 2025-06-19 15:43:37 +08:00
李通洲 4f42d38e4d GPU (FreeBSD): fix mem leaks 2025-06-18 20:20:49 +08:00
李通洲 7b2243496b GPU (Windows): fix build 2025-06-18 18:53:29 +08:00
Carter Li 960a817d03 GPU (Linux): fix building without features 2025-06-18 18:37:30 +08:00
Carter Li 6917f9479e GPU (Linux / FreeBSD): add DRM detection support for old radeon driver
Ref: #1810
2025-06-18 16:41:02 +08:00
Carter Li 8559cc45eb GPU (Linux / FreeBSD): unifies DRM related code and code clean up 2025-06-18 10:01:32 +08:00
李通洲 40e33c676d GPU (FreeBSD): support detection by DRM [wip] 2025-06-17 20:58:09 +08:00
李通洲 d20371040e WM (FreeBSD): fix Hyprland version detection 2025-06-17 20:38:10 +08:00
李通洲 71faf1c7e3 GPU (macOS): detect Metal 4 support 2025-06-17 14:07:18 +08:00
李通洲 d182f3f743 OS (macOS): seems macOS 26 Beta 1 still reports itself as macOS 16. Honor it. 2025-06-17 14:01:22 +08:00
李通洲 39e009b945 CI: upgrade OpenBSD version 2025-06-17 09:30:14 +08:00
李通洲 a1873f3e9e CI: split amd64 and arm64 builds
So we can test both platforms in CI
2025-06-17 09:01:38 +08:00
李通洲 636bcaaaf9 Kmod: remove Chinese comments [ci skip] 2025-06-17 08:43:09 +08:00
李通洲 3fcbd80ef0 Board (macOS): detect board-id if available
Ref: https://github.com/GuillaumeGomez/sysinfo/pull/1545
2025-06-17 00:06:31 +08:00
李通洲 38887e7fbd Logo (Builtin): add GhostFreak
Fix #1801
2025-06-15 12:28:45 +08:00
AVSISP da958e11f9 Logo (Builtin): added AnushOS (#1806)
* Added AnushOS to builtin.c

Added AnushOS config to builtin.c

* Create anushos.txt

Added anushos.txt to ASCII logos

* Update builtin.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-15 12:23:27 +08:00
李通洲 c2ed71c4eb Global: set SetErrorMode(SEM_FAILCRITICALERRORS) globally
Fix #1805
2025-06-15 00:00:22 +08:00
ᡥᠠᡳᡤᡳᠶᠠ ᡥᠠᠯᠠ·ᠨᡝᡴᠣ 猫 2e1ddcf9f8 Logo (Builtin): Add HarmonyOS support (#1804)
* Logo (Builtin): add HarmonyOS

* OS (HarmonyOS): detect HarmonyOS

* Update src/detection/os/os_linux.c

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update os_linux.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-14 09:03:57 +08:00
Carter Li f1cc2d124c Packages (OpenBSD): fix counting by ignoring hidden folders 2025-06-13 20:38:51 +08:00
Techflash 1e32a95f83 CPU (NetBSD): properly support PowerPC (#1802)
Some devices store their CPU name in hw.model, so check that as well
before giving up.  Tested on NetBSD 10.1 evbppc/wii, and allows it to
detect the CPU as "750 (Revision 2.0)".

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-11 00:15:40 -05:00
CopticFelo 9e959bc57f WM (MacOS): Added Aerospace WM detection 2025-06-10 11:22:31 +08:00
李通洲 e68406ee22 DE (macOS): report Liquid Glass on macOS 26+ 2025-06-10 10:56:13 +08:00
李通洲 ba69e316b2 OS (MacOS): add macOS 26 Tahoe 2025-06-10 10:48:35 +08:00
李通洲 f3e8e8af52 Logo (Builtin): detect and add TrueNAS Scale 2025-06-10 10:22:13 +08:00
李通洲 c9adab3892 OS (Linux): detect Raspberry Pi OS
Fix #1773
2025-06-10 09:55:13 +08:00
李通洲 c8d1d29017 Disk (Linux): hide /boot/firmware by default 2025-06-10 09:54:11 +08:00
Carter Li 541acca7c0 Logo (Builtin): add xenia_old; update colors of xenia
#1797
2025-06-10 09:13:21 +08:00
Derek Passen ddf5099461 TerminalFont: support rio terminal emulator (#1789)
* Enable terminal font detection for rio terminal emulator

https://rioterm.com
https://rioterm.com/docs/config
https://rioterm.com/docs/config#fonts

* Update src/detection/terminalfont/terminalfont.c

Fix default rio font name

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-08 00:00:03 +08:00
李通洲 781a692b06 JsonSchema: document swap.separate 2025-06-07 19:23:25 +08:00
李通洲 9c37f1b370 CPU (Windows): use perflib.h instead of pdh.h for querying CPU temp
Fix #1787
2025-06-07 19:17:46 +08:00
Carter Li a66c26f4df Logo (Builtin): improve colors of bedrock_small
Fix #1790
2025-06-07 17:39:45 +08:00
Carter Li 3bd750bedf Host (Linux): detect Linux Binary Compatibility on FreeBSD
Fix #1786
2025-06-06 15:38:46 +08:00
Carter Li 4a1ada604c Host (Linux): more detailed info of WSL 2025-06-06 14:49:32 +08:00
Noah Michaels e5f57a34a2 Logo (Builtin): Add Fedora2_small (#1785)
* Add 1 more small Fedora logo

* Update builtin.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-06-05 20:12:44 -05:00
Carter Li 20a3737dce Packaging: update debian stuff [ci skip] 2025-06-05 10:59:16 +08:00
Carter Li e0452d9db5 Merge pull request #1784 from fastfetch-cli/dev
Release: v2.45.0
2025-06-05 10:47:05 +08:00
李通洲 d8e74ba84c Release: v2.45.0 2025-06-05 10:13:56 +08:00
Carter Li 04b13096ac Swap (Haiku): detect detailed info 2025-06-04 22:01:16 +08:00
李通洲 64d4035cae Chore (Haiku): don't use hard-coded page size 2025-06-04 21:26:37 +08:00
Carter Li 5e0ba57f53 Disk (BSD): silence compiler warnings 2025-06-05 04:55:12 +08:00
李通洲 d89263c218 Swap (DragonFly): add support 2025-06-04 20:51:21 +08:00
Carter Li 6a42588786 Swap (SunOS): detect detailed info 2025-06-04 19:36:22 +08:00
Carter Li 5883bf359c Swap (OpenBSD): detect detailed info 2025-06-04 19:05:02 +08:00
Carter Li 6a6b4070ca Swap (Linux): add fallback for Android 2025-06-04 18:35:53 +08:00
Carter Li 2c80cd6d29 Swap (Linux): support detailed info 2025-06-04 16:44:10 +08:00
Carter Li fa4b00b027 Swap (FreeBSD): detect detailed info 2025-06-04 15:30:03 +08:00
李通洲 5fdc924b5d Swap (macOS): detect detailed info 2025-06-04 15:07:05 +08:00
李通洲 3d4a117093 Swap: support separated output 2025-06-04 15:02:02 +08:00
李通洲 7ec0c664c5 Swap (Windows): detect detailed info 2025-06-04 15:01:37 +08:00
李通洲 9d2df589b5 Smbios (DragonFly): acquire SMBIOS info from /dev/mem 2025-06-04 14:22:33 +08:00
李通洲 7107d08e92 DE (DragonFly): fix build 2025-06-04 14:22:33 +08:00
Carter Li 4c34f99c12 Swap (Linux): use /proc/swaps
Preparing for detailed swap usage
2025-06-04 10:37:07 +08:00
Carter Li d7a8c92b46 CI (Linux): fix musl build 2025-06-04 09:05:04 +08:00
李通洲 bbb29ff766 CI (Linux): add missing deps for musl 2025-06-03 21:15:48 +08:00
amnexya 35235b9557 Logo (Builtin): Update logo for Xenia Linux (#1783)
* Update Xenia Linux logo

* Update builtin.c for xenia colours

* Update src/logo/builtin.c

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-03 21:11:50 +08:00
Carter Li 6b94605804 Disk (BSD): don't ignore sshfs 2025-06-03 18:58:38 +08:00
Carter Li 4b2fa07fdc Packages (Linux): fix dnf package count detection (v2) 2025-06-03 10:53:02 +08:00
Carter Li e203f4eeaf Packages (Linux): fix dnf package count detection
Fix #1777
2025-06-03 09:33:43 +08:00
李通洲 8db70b40e2 CI: add back disabled DFBSD 2025-06-02 22:00:32 +08:00
李通洲 1f967849e5 CMake: fix build of FreeBSD 2025-06-02 19:15:14 +08:00
李通洲 d60b2ddfd4 Disk (Linux): don't ignore sshfs
Fix #1776
2025-06-02 19:09:24 +08:00
李通洲 fb68d8a841 CI (Haiku): add build
Disabled due to https://github.com/cross-platform-actions/action/issues/104
2025-06-02 18:48:16 +08:00
李通洲 047411ba87 CMake: build FreeBSD pkg package 2025-06-02 15:56:18 +08:00
李通洲 08ed14b42a Logo: support "type": "command-raw"
Fix #1780
2025-06-02 11:46:43 +08:00
李通洲 d94a41cc1b Chore: tidy 2025-06-02 11:46:43 +08:00
Anshnk 81b7fb06c1 Fix typo, 15,2 isn't a real mac model number 2025-06-02 11:02:10 +08:00
李通洲 c8debccd16 DE (FreeBSD): support KDE version detection 2025-06-02 10:19:36 +08:00
Carter Li 2853bd15c0 Logo (Builtin): add void2
Ported from hyfetch
2025-05-31 23:28:16 +08:00
Carter Li 2f4146fde8 Logo (Builtin): update default colors of voidlinux
Fix  #1775
2025-05-31 23:18:43 +08:00
李通洲 eeceade14e Logo (Builtin): add rhel_small
Fix #1774
2025-05-31 13:39:40 +08:00
李通洲 1875c78e96 WM: support I3 version detection 2025-05-31 10:41:38 +08:00
李通洲 f389864e17 WM: support FVWM version detection 2025-05-31 10:16:26 +08:00
李通洲 b9317734b9 WM: support CTWM version detection 2025-05-31 10:02:45 +08:00
李通洲 4df4a1de78 Logo (Builtin): add Starry Linux
Fix #1771
2025-05-30 13:56:52 +08:00
李通洲 0cd8c6ead6 Chore: code cleanup 2025-05-30 10:33:37 +08:00
李通洲 f8479dae94 GPU: add more GPU vendors 2025-05-30 10:33:26 +08:00
李通洲 a7d623fa75 JsonSchema: update <module>Format [ci skip] 2025-05-29 10:13:57 +08:00
李通洲 7a8ffb27bd Packages: split code 2025-05-26 15:12:47 +08:00
Carter Li 73c0347469 Merge remote-tracking branch 'origin/dev' into dev 2025-05-26 15:00:58 +08:00
Carter Li fde5f3bd0f Packaging: update debian stuff [ci skip] 2025-05-26 15:00:06 +08:00
李通洲 9e1b1302fb Host (Android): add detection for OnePlus market name
Fix #1768
2025-05-26 14:22:47 +08:00
Carter Li 7e235b6be0 Merge pull request #1766 from fastfetch-cli/dev
Release: v2.44.0
2025-05-23 16:10:12 +08:00
李通洲 f43e1fd614 Release: v2.44.0 2025-05-23 15:41:22 +08:00
Carter Li c7b061eebd DisplayServer (Linux): fix errors on KDE beta
Fix #1765
2025-05-22 09:41:35 +08:00
Carter Li a0f579072f Disk: add --disk-hide-fs
Fix #1762
2025-05-21 16:40:42 +08:00
Carter Li d439ce8eb5 Disk: rename hiddenFolder to hideFolder; add docs 2025-05-21 15:09:19 +08:00
Carter Li e2a714732a Disk: add hiddenFolders (2) 2025-05-21 15:00:42 +08:00
asmeron a993a6f126 Logo (Builtin): Add UBLinux Logo (#1764)
* Logo (Builtin): Add UBLinux Logo

* Update builtin.c

---------

Co-authored-by: asmeron <asmeron@ublinux.com>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-05-20 21:50:34 -05:00
李通洲 8eb8f710d0 Disk: add option --disk-hidden-folders 2025-05-19 18:32:56 +08:00
李通洲 526868e355 Disk (Linux): don't hard code hidden mount points 2025-05-19 15:25:06 +08:00
李通洲 768238cb46 TerminalShell (Linux): ignore script
Fix #1761
2025-05-17 18:04:41 +08:00
Xavier Xiong 2d938042d0 Logo (Builtin): Add Kylin Logo (Remove ANSI codes) (#1760)
* Logo (Builtin): Add Kylin Logo

* Remove all ANSI escape codes from ASCII Logo

* Add color prefix to kylin logo
2025-05-16 01:05:42 -05:00
李通洲 9a54d92e9f Stat: use ESC 7/8 instead of CSI s/u
Fix Apple Terminal compatibility #1755
2025-05-16 10:33:58 +08:00
Collin 839abab744 Doc: Add information of where to find example config files (#1759) [ci skip] 2025-05-15 19:58:36 -05:00
Md. Iftakhar Awal Chowdhury c054570308 fish complete: add --logo-color-[1-9] completion (#1754)
* fish complete: add `--logo-color-[1-9]` completion

* reverted unnecessary changes
2025-05-15 03:18:19 -05:00
Carter Li ed69a7059b Packaging: update debian stuff [ci skip] 2025-05-14 09:51:44 +08:00
Carter Li 6b92659512 Merge pull request #1752 from fastfetch-cli/dev
Release: v2.43.0
2025-05-14 09:41:33 +08:00
Carter Li 7e04305d1c CI: silence spell check errors 2025-05-14 09:25:15 +08:00
Carter Li 87e13543da GPU (Linux): embed asahi_drm.h 2025-05-14 08:59:53 +08:00
Carter Li 7a2cbc060f 3rdparty (yyjson): upgrade to 0.11.1 2025-05-14 08:52:06 +08:00
Carter Li f22d73d473 PhysicalDisk: trim white spaces of serial 2025-05-13 18:29:46 +08:00
李通洲 e629126d73 Doc: update changelog 2025-05-13 15:52:30 +08:00
李通洲 9ac635e2e6 Media (Windows): detect player name (UMP apps only) 2025-05-13 15:46:33 +08:00
李通洲 1b1b0521f4 Doc: update changelog 2025-05-13 13:49:54 +08:00
李通洲 41d0f61ee0 GPU (AMD): remove usage of ADL2_Adapter_VRAMUsage_Get
It reports dedicated GPU memory usage too.

Ref: https://github.com/GPUOpen-LibrariesAndSDKs/display-library/issues/48
2025-05-13 13:39:42 +08:00
李通洲 9de5d9008b Release: v2.43.0 2025-05-13 10:37:52 +08:00
李通洲 576a9cc6fe Revert "Vulkan: use VK_API_VERSION_* instead of deprecated VK_VERSION_*"
Breaks building with old vulkan-headers

This reverts commit 36b0fdbcda.
2025-05-13 10:02:38 +08:00
李通洲 bd61d08afe Sound (macOS): report the volume of muted device as 0% 2025-05-13 09:35:13 +08:00
李通洲 4672b78481 Sound: don't show 255 in custom format
Fix #1750
2025-05-13 09:30:30 +08:00
李通洲 36b0fdbcda Vulkan: use VK_API_VERSION_* instead of deprecated VK_VERSION_* 2025-05-13 09:29:21 +08:00
Carter Li 7626ef6eaa GPU (Linux): fix CI errors
F**k Ubuntu
2025-05-10 21:40:33 +08:00
Carter Li 115108b3f1 GPU (Linux): detect core usage when libamdgpu is not available 2025-05-10 20:57:51 +08:00
Carter Li 154f9f462b GPU (Linux): detect VRAM type of AMD GPUs 2025-05-10 20:57:51 +08:00
Marvin Friedrich a96a9fc31d Smbios: fix transitive include for loff_t (#1746) 2025-05-10 10:49:22 +08:00
李通洲 23b43244c5 GPU (AMD): seems ADL2_Adapter_VRAMUsage_Get reports system mem usage only, not full memory usage
Because VRAMUsage reports a value which is smaller than DedicatedVRAMUsage
2025-05-09 22:46:31 +08:00
Carter Li 9dfb404a0d GPU (AMD): more verbose logs 2025-05-09 22:01:29 +08:00
Carter Li ff3028c656 GPU: don't hide unknown type of GPUs by default
Fix #1742
2025-05-09 21:58:41 +08:00
Carter Li 2f706ed494 Smbios: discard usless values 2025-05-09 21:55:31 +08:00
Carter Li 06427ee62b Media (Linux): fix duplicated playback status 2025-05-09 19:23:28 +08:00
李通洲 fe66eb3df0 GPU (Windows): fix incorrect used shared memory size 2025-05-08 23:20:53 +08:00
李通洲 6e1ab12399 Memory / Swap: always initialize local variables 2025-05-08 23:17:22 +08:00
Samuli Thomasson 484e05eae3 GPU: optionally hide unknown GPUs (#1742)
The current default behavior of not hiding any GPUs is retained. The new
feature of hiding unknown or unrecognized GPUs can be enabled with
hide-type = "unknown".
2025-05-07 22:06:47 +08:00
Joe_ 5d3fb98072 Logo (Builtin): add Hydra Framework logo (#1740)
* Added: Hydra Framework logo

* Remove extra line: hydra.txt
2025-05-07 03:02:36 -05:00
李通洲 0c30590088 Builtin (Logo): new AthenaOS logo
Fix #1741
2025-05-07 10:45:21 +08:00
李通洲 20cd4ce125 Logo (Builtin): sd '\$\{c(\d)\}' '$$$1' * 2025-05-07 10:44:05 +08:00
apocelipes 1c7aa89228 TerminalShell: use ffBinaryExtractStrings result as possible (#1739) 2025-05-06 18:49:29 +08:00
apocelipes f270255770 DisplayServer (Linux): fix xcb_connect error handling (#1735) 2025-05-06 03:18:53 -05:00
李通洲 4b62a3c75b 3rdparty: upgrade yyjson to 0.11.0 2025-05-06 16:12:58 +08:00
李通洲 1557f0c556 Media (macOS): support macOS 15.4
Fix #1737
2025-05-06 16:12:58 +08:00
Carter Li ef7f61309f GPU (Linux): fix asahi linux support again
Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
2025-05-06 09:27:54 +08:00
李通洲 f59491b25d Disk (Linux): fix possible bug on 32-bit platforms
Fix #1734
2025-05-05 22:05:22 +08:00
李通洲 e3592eb2c3 CPU (FreeBSD): simplify physical core count detection 2025-05-05 13:41:12 +08:00
Carter Li 305776eb94 CPU (SunOS): support physical core count and package count detection 2025-05-02 14:24:30 +08:00
Carter Li 599e0d393d Display: use height to calculate scale factor
Seems more accurate
2025-05-01 21:28:04 +08:00
李通洲 561574ae94 CPU (Windows): always use XxxW 2025-04-30 16:10:53 +08:00
李通洲 3dd78422eb Global: Improve ARRAY_SIZE macro using __is_array 2025-04-30 14:47:37 +08:00
李通洲 5c546ab8e7 Parsing: silence compiler warnings 2025-04-30 14:14:28 +08:00
Carter Li 3e9274040d Packaging: update debian stuff [ci skip] 2025-04-30 14:12:26 +08:00
Carter Li 630d876e2d Merge pull request #1722 from fastfetch-cli/dev
Release: v2.42.0
2025-04-29 14:05:36 +08:00
李通洲 1938be86ff Wifi (NetBSD): fix the ambiguous comment 2025-04-29 13:53:45 +08:00
李通洲 0980d5f0ad Wifi (BSD): correctly prioritize Wi-Fi protocol detection
by using an `if-else if` chain
2025-04-29 13:50:53 +08:00
李通洲 d8c1b3b61b Release: v2.42.0 2025-04-29 10:38:07 +08:00
李通洲 969523ae8a BIOS: normalize the module name
Fix #1721
2025-04-29 10:26:19 +08:00
李通洲 5d960ec744 Uptime: fix non-normalized time being shown
Fix #1720
2025-04-29 10:22:19 +08:00
apocelipes 3b36b8ca57 Global: use ARRAY_SIZE (#1718) 2025-04-28 21:22:04 -05:00
apocelipes 05f14764e6 Bluetooth (Linux): silence an unused variable warning (#1717) 2025-04-28 22:50:46 +08:00
apocelipes 3a180b24e3 Platform: fix a memory leak (#1716) 2025-04-28 22:49:31 +08:00
李通洲 02ab58e001 Doc: update changelog [ci skip] 2025-04-24 09:31:05 +08:00
Carter Li fd158b41e1 Logo (Chafa): fix setting chafa.symbols
Fix #1709
2025-04-24 09:02:45 +08:00
李通洲 89e0ede12f Camera (OpenBSD): add support 2025-04-23 20:09:08 +08:00
李通洲 4d7b2410ef CPU (OpenBSD): fix CPU temperature detection 2025-04-22 21:19:22 +08:00
李通洲 c1f6a2f755 Refactor: inline printError into ffPrintError and remove unused static helper 2025-04-22 14:30:39 +08:00
李通洲 9c455c3b0f Wifi (FreeBSD): fix possible mem leaks 2025-04-20 12:41:06 +08:00
Carter Li d4ea9dfd21 Wifi (NetBSD): add support
Untested
2025-04-20 12:40:47 +08:00
李通洲 08071e6e7e Wifi (OpenBSD): fix file name 2025-04-20 11:49:40 +08:00
李通洲 ec87174f30 CPU (NetBSD): add one more method to detect CPU frequency 2025-04-20 11:43:39 +08:00
李通洲 835e5b51c9 CPU (SunOS): detect CPU temp
Untested
2025-04-20 11:12:08 +08:00
Noa Himesaka 07c5ef255e Logo (Builtin): Add Codex Linux support (#1701)
* feat: add Codex Linux

* Codex.txt: remove empty lines

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-04-19 21:22:28 +08:00
李通洲 476b55c17d Logo (Builtin): remove GoralixOS
Ref: #1699
2025-04-19 21:18:13 +08:00
李通洲 4a53cfa312 Logo (Builtin): add Aurora
Fix #1700
2025-04-19 21:11:54 +08:00
李通洲 50ea515476 PhysicalDisk (Linux): don't detect disk type of virtual disks
Fix #1697
2025-04-18 16:10:01 +08:00
xzvf cbd9f72bc8 T2/SDE: upstreaming downstream's logo change (#1695)
* T2/SDE: upstreaming downstream's logo change

T2/SDE port of fastfetch applies two patches, improving the
distribution's logo and adding alternative names. I see no point not
having these upstream.

Downstream's patches are found here:
https://github.com/rxrbln/t2sde/tree/main/package/contrib/fastfetch

The old logo has been renamed to "T2_small".

* Fix ASCII art alignment in t2.txt

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-04-17 22:52:45 +08:00
李通洲 29eaa35f4c Color: support #RGB and #RRGGBB
Fix #1694
2025-04-17 10:48:18 +08:00
Carter Li 97c89c39d3 Packaging: update debian stuff [ci skip] 2025-04-16 13:51:09 +08:00
Carter Li 5769791185 Merge pull request #1691 from fastfetch-cli/dev
Release: v2.41.0
2025-04-16 13:29:07 +08:00
李通洲 894c66d793 Processing (Windows): fix macro name __aarch64__
Found by AI
2025-04-16 11:12:36 +08:00
李通洲 75290154b0 Chore: remove Chinese comments [ci skip] 2025-04-16 11:09:03 +08:00
李通洲 b08eea76b1 CI (Linux): enable chafa on Linux aarch64 2025-04-16 10:45:25 +08:00
李通洲 61d83af9ea CI (Linux): bump GH runner for linux-amd64
Ref: https://github.com/actions/runner-images/issues/11101
2025-04-16 10:45:02 +08:00
李通洲 2d497038eb Release: v2.41.0 2025-04-16 09:24:20 +08:00
李通洲 f8a5d5561a Bluetooth (NetBSD): add base implementation
Ref: #1690
2025-04-15 19:06:39 +08:00
李通洲 2e7e68ef23 Doc: add installation instructions for pkgsrc [ci skip]
Fix #1689
2025-04-15 19:04:19 +08:00
李通洲 b812f3ccde Uptime (Windows): use QueryUnbiasedInterruptTime
As suggested by MSDN
2025-04-15 16:41:38 +08:00
李通洲 6da8181bbe CMake: use mincore on WoA 2025-04-15 16:41:38 +08:00
李通洲 a51dd641c1 Processing (Windows): use GetOverlappedResultEx on WoA 2025-04-15 16:41:38 +08:00
李通洲 0d20164d40 CI (Windows): add WoA 2025-04-15 10:59:10 +08:00
李通洲 3320532668 GPU (Linux): add temp detection for Intel GPU
Untested
2025-04-14 18:57:15 +08:00
Carter Li bcc6492115 NetIO (Linux): use openat 2025-04-14 18:48:04 +08:00
naix c60bc8ee5b Logo (Builtin): Add 2 more Alpine logos (#1687)
* Logo (Builtin): Add 2 more Alpine logos

* Remove unnecessary $1 in ASCII logo file

* Add type field to Alpine2 logo configuration

---------

Co-authored-by: naix <naix@noreply.codeberg.org>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-04-14 00:50:45 -05:00
李通洲 4eefab8ccf CPU (Linux): fix build 2025-04-14 10:54:35 +08:00
李通洲 9cda7e20fb Chore: simplify fastfetch.h 2025-04-14 10:28:01 +08:00
李通洲 79d0197dcf Wifi (FreeBSD): remove unused sys headers 2025-04-14 10:04:11 +08:00
李通洲 ba01b1e4ce CPU (Linux): add new ARM part numbers 2025-04-14 09:27:01 +08:00
李通洲 58908f69ba Wifi (OpenBSD): add support
Completely untested.
2025-04-13 00:37:40 +08:00
李通洲 114088b845 Doc: add comments about displaying image logo on Windows [ci skip]
Fix  #1686
2025-04-12 20:38:42 +08:00
李通洲 6e77b592cb WM (FreeBSD): enable Hyprland version detection 2025-04-12 10:48:26 +08:00
李通洲 73bc71e922 CPU (Windows): use PDH to detect thermal temp
No Administrator privileges needed
2025-04-12 10:47:57 +08:00
Anduin Xue 090529ffef Logo (Builtin): Add support for anduinos (#1684)
* Add anduinos

* fix logo.

* Update anduinos.txt
2025-04-10 23:13:26 +08:00
李通洲 3c291f1af9 Platform: retrieve full user name 2025-04-09 16:15:23 +08:00
李通洲 fc31fe4aa4 Merge branch 'master' into dev 2025-04-09 14:39:51 +08:00
李通洲 563f9598be Release: v2.40.4 2025-04-09 14:24:27 +08:00
Carter Li 03bc2dade9 Fastfetch: fix loading presets in {exePath}/presets
Regression of v2.40.0
2025-04-09 14:15:06 +08:00
Carter Li 09d683b706 WM (Linux): remove v from Hyprland version 2025-04-09 14:14:56 +08:00
Carter Li 523a9590b8 Fastfetch: fix loading presets in {exePath}/presets
Regression of v2.40.0
2025-04-08 15:42:58 +08:00
李通洲 3c3188eb05 IO (Windows): support ~ expanding 2025-04-07 16:43:48 +08:00
李通洲 354062118f Chore: update comment 2025-04-07 16:43:48 +08:00
李通洲 85d7390fa8 Util (Windows): use native win32 functions 2025-04-07 16:38:54 +08:00
Carter Li 8509f97054 WM (Linux): remove v from Hyprland version 2025-04-06 17:21:32 +08:00
Rabindra Dhakal 8d5d8b4c90 Packages (Linux): add soar packages count (#1531)
* add soar packages count

* use || instead of concat for better compatibility with older SQLite versions

* convert package flags to 64-bit
2025-04-05 23:54:27 +08:00
李通洲 536ad9594e PhysicalDisk (Linux): add more disk types 2025-04-05 22:35:42 +08:00
李通洲 a57bbbadf4 PhysicalDisk (Linux): don't detect disk type for virtual disks
Fix #1669
2025-04-05 22:35:42 +08:00
李通洲 3def466ee0 Revert "CPU (FreeBSD): remove using of freq_levels"
This reverts commit ed2dd8f2ec.
2025-04-05 13:54:20 +08:00
李通洲 59868c66a0 CPU (FreeBSD): don't assume one SMT group has only two threads
Fix #1670
2025-04-05 13:48:18 +08:00
Carter Li e13eb05073 CPU (Linux): detect physical core count on non-x86 platforms 2025-04-05 12:08:35 +08:00
Carter Li cdda65e6ad Merge pull request #1673 from fastfetch-cli/dev
Release: v2.40.3
2025-04-05 09:14:34 +08:00
Carter Li a7ac89818c Logo (Image): mark kitty image protocol support for warp terminal on macOS 2025-04-05 08:59:35 +08:00
李通洲 06956d2cf4 Release: v2.40.3 2025-04-05 08:42:24 +08:00
李通洲 ac52ea1afb Fastfetch: fix loading example configs from presets directory
Fix #1672
2025-04-05 08:42:24 +08:00
Carter Li b68e0ce8ae Merge pull request #1668 from fastfetch-cli/dev
Release v2.40.2
2025-04-04 19:38:49 +08:00
李通洲 8d6ed2e847 Release: v2.40.2 2025-04-04 19:23:22 +08:00
李通洲 4211d15cdb Doc: fix CI errors (2) 2025-04-04 19:12:01 +08:00
李通洲 2ff8d8864d Doc: fix CI errors 2025-04-04 19:07:56 +08:00
李通洲 884c902d93 Doc: migrate some help texts to Github Wiki pages 2025-04-04 18:59:15 +08:00
李通洲 16c56254b0 Doc: update documents 2025-04-04 18:51:31 +08:00
李通洲 88eaab670f Doc: update README 2025-04-04 16:18:57 +08:00
李通洲 3e7630e074 Fastfetch: enforce .jsonc extension when loading config file
Examples:
1. `-c filename`: load `filename.jsonc`
2. `-c filename.jsonc`: load `filename.jsonc`
3. `-c filename.json`: load `filename.json` and enforce strict JSON syntax (no comment and trailing comma support)
4. `-c filename.ext`: load `filename.ext.jsonc` (`jsonc` extension is enforced)
2025-04-04 14:45:48 +08:00
李通洲 744455d8b7 Logo (Image): default to kitty protocol in warp terminal
Fix #1666
2025-04-04 14:41:06 +08:00
Carter Li bcc8f6d0b8 Merge pull request #1665 from fastfetch-cli/dev
Release v2.40.1
2025-04-04 00:45:57 +08:00
Carter Li 90ca6ee3cd Release: v2.40.1 2025-04-04 00:27:11 +08:00
李通洲 b679185c87 Logo: don't try to find files named - 2025-04-03 22:42:15 +08:00
李通洲 6bbed12083 IO: remove fast path of ffPathExists, which causes too many problems
Fix #1662
2025-04-03 22:38:05 +08:00
李通洲 f04851891e TPM (macOS): fix compiling error on old system
Fix #1659
2025-04-03 16:21:02 +08:00
Carter Li f94d9ca3bd Packaging: update debian stuff [ci skip] 2025-04-03 08:49:01 +08:00
Carter Li f833dda3b9 Merge pull request #1656 from fastfetch-cli/dev
Release: v2.40.0
2025-04-03 08:41:21 +08:00
李通洲 ceecb39bc5 WM (Linux): fix https://github.com/fastfetch-cli/fastfetch/issues/1657#issuecomment-2772749780 2025-04-02 23:22:34 +08:00
Carter Li c957ca7230 WM (Linux): query Hyprland version from hyprland dev header 2025-04-02 19:15:09 +08:00
李通洲 5dfd2676c2 Binary: add comments 2025-04-02 10:35:42 +08:00
李通洲 d650f67ece WM (Linux): correctly fall back to calling wm --version if ffBinaryExtractStrings fails
Fix #1657
2025-04-02 10:35:42 +08:00
李通洲 760e82913a CI: remove Dragonfly BSD
Ref: #1632
2025-04-02 08:53:51 +08:00
Carter Li e64a44a3e6 WM (Linux): fix (?) Hyprland version detection 2025-04-02 00:12:21 +08:00
李通洲 be9cf00b05 Release: v2.40.0 2025-04-01 20:20:06 +08:00
李通洲 52fdabeb2e Uptime: round seconds to the nearest minute
To match the behavior of `uptime` command
2025-04-01 19:40:15 +08:00
李通洲 846f4c003e DisplayServer (Linux): silence compiler errors 2025-04-01 19:15:21 +08:00
李通洲 dc5f2ac577 Util (Windows): fix mem leaks 2025-04-01 19:15:20 +08:00
李通洲 663650cb61 Util (Windows): fix possible errors in Unicode.c 2025-04-01 19:15:20 +08:00
李通洲 45aecae221 Util (Linux): fix executable file check 2025-04-01 19:02:35 +08:00
李通洲 3d3669ae3a FFlist: use uint8_t instead of char to store raw data 2025-04-01 19:02:35 +08:00
李通洲 ac2aba0faf Threading: fix timeout calcuation 2025-04-01 11:07:28 +08:00
李通洲 d0ca944b9c Netif (Linux): support default route detection for ipv6 2025-04-01 10:48:30 +08:00
李通洲 3d7c631abd Wifi: fix code smells 2025-04-01 10:48:04 +08:00
Carter Li abe78823b6 PhysicalMemory (Linux): code refactor 2025-04-01 09:43:37 +08:00
李通洲 7e03b03cb7 Users (Linux): support IPv6 client addr 2025-04-01 09:43:37 +08:00
李通洲 27fe997dc3 Users (Windows): support IPv6 client IP 2025-03-31 23:41:54 +08:00
李通洲 fe46159e40 Uptime (NetBSD): fix boot time calcuation 2025-03-31 23:40:35 +08:00
李通洲 031aa985f1 TPM (macOS): add support 2025-03-31 23:40:01 +08:00
李通洲 07c61f70d9 InitSystem (Haiku): set pid=0 if fails to detect init pid 2025-03-31 23:39:25 +08:00
李通洲 71b05d2594 Doc: update changelog [ci skip] 2025-03-31 21:43:43 +08:00
李通洲 98665d1b82 Revert "CI: build in debug mode"
This reverts commit e05ac797cc.
2025-03-31 19:08:02 +08:00
李通洲 da0eedf888 Swap (Windows): support multiple paging files 2025-03-31 18:56:03 +08:00
李通洲 1133cb619b Swap (OpenBSD): fix mem leaks 2025-03-31 18:56:03 +08:00
李通洲 a091d209cf Swap: fix code smells 2025-03-31 18:44:41 +08:00
李通洲 47c658815b Sound: fix typo and mem leaks 2025-03-31 16:38:58 +08:00
李通洲 b0d0c74073 Doc: update changelog [ci skip] 2025-03-31 10:59:55 +08:00
李通洲 9535b4d480 Chore (Windows): silense compiler warnings 2025-03-31 10:48:14 +08:00
Carter Li c64cbf57d8 fastfetch: load config from fastfetch binary path
Fix #1649
2025-03-31 10:48:09 +08:00
komaru.yml d11235bbe2 Logo (Ascii): Change Nexa Linux logo (#1653) 2025-03-31 08:51:48 +08:00
Angel Gustavo Lopez 3054c6618e Logo (Builtin): change name of Xray-OS 2025-03-30 21:48:47 +08:00
李通洲 f34d51dddc Terminal (Windows): fix file version detection 2025-03-30 16:38:54 +08:00
李通洲 e05ac797cc CI: build in debug mode 2025-03-29 20:42:42 +08:00
李通洲 187059deef GPU (Windows): fix max frequency detection for AMD ODN 2025-03-29 20:42:42 +08:00
李通洲 5c9f184314 GPU (Windows): use ODN as OD7; fix ADL2_Overdrive8_Current_Setting_Get call and some other bugs 2025-03-29 17:03:56 +08:00
李通洲 49725c2cc6 Doc: update changelog [ci skip] 2025-03-28 16:32:13 +08:00
李通洲 eec9a26952 TerminalFont (Windows): support Warp Terminal 2025-03-28 15:26:30 +08:00
李通洲 88d616e978 GPU (Windows): try more OD funcs; add more verbose logs 2025-03-28 14:57:43 +08:00
李通洲 4fccad5d10 Disk (macOS): silense compiler warnings 2025-03-28 14:57:43 +08:00
李通洲 ec18363f51 DNS (macOS): detect DNS entries by SystemConfiguration 2025-03-28 10:49:20 +08:00
Carter Li b87a36785b DNS (Linux): add systemd-resolved support; add verbose logs 2025-03-28 09:50:33 +08:00
李通洲 1d7b212d8d Media: fix code smells 2025-03-27 16:44:14 +08:00
李通洲 4b6f2a9efa Gamepad / Keyboard / Mouse (FreeBSD): break detection earlier 2025-03-27 14:40:33 +08:00
李通洲 bdaf303da4 Keyboard (FreeBSD): fall back to KDGKBINFO if usbhid fails 2025-03-27 14:15:25 +08:00
李通洲 3fb773eedd Gamepad / Mouse / Keyboard (FreeBSD): fix memleaks 2025-03-27 14:08:01 +08:00
李通洲 e73647973d Host (Windows): fix build on WoA 2025-03-27 09:38:32 +08:00
李通洲 d2b3a075b2 GPU (Windows): actually use correct OD fns for recent AMD GPUs 2025-03-27 09:29:21 +08:00
李通洲 f139148745 GPU (Windows): add OverdriveN functions for AMD 2025-03-26 23:55:23 +08:00
Carter Li e2ec2c695c GPU (Windows): fix ADL2_Adapter_AdapterInfoX3_Get result test 2025-03-26 22:22:44 +08:00
李通洲 ba4ec47a8c GPU (Windows): added verbose logs 2025-03-26 21:10:51 +08:00
李通洲 de5ef3842c Global: fix code smells 2025-03-26 16:44:52 +08:00
李通洲 1129ed9be4 Host (macOS): add new models; fix an invalid model ID 2025-03-26 16:27:15 +08:00
李通洲 0d4f1544c7 Chore: fix code smell 2025-03-26 14:42:55 +08:00
李通洲 e68a9476b5 Disk (SunOS): remove creation time detection support
ctim is `Timestamp of last file status change`, not creation time
2025-03-26 11:02:57 +08:00
李通洲 17556c7a95 Util/debug: add missing #pragma once 2025-03-26 09:47:33 +08:00
李通洲 eca9f626a5 Separator: fix outputColor doesn't work when length is set
Fix #1644
2025-03-25 23:22:25 +08:00
李通洲 7562e05123 Chore: fix a lot code smell 2025-03-25 22:08:50 +08:00
李通洲 bf17f2b4b9 LocalIP: change {name} to {ifname} in --localip-key-format for consistancy
Breaking change.

Fix #1639
2025-03-25 22:08:50 +08:00
李通洲 88e193e9fd GPU: fix code smell 2025-03-25 22:08:50 +08:00
李通洲 e474a47fad GPU (General): fix GPU device type detection 2025-03-25 22:08:50 +08:00
李通洲 c77fb71a69 Battery (NetBSD): report remaining time 2025-03-25 22:08:49 +08:00
李通洲 48dd5976e1 Battery (Linux): fix critical state detection 2025-03-25 22:08:49 +08:00
李通洲 093f7e438b Battery (macOS): fix manufacture date detection 2025-03-25 22:08:49 +08:00
李通洲 0a0c1745b3 GPU (macOS): fix code smell 2025-03-25 22:08:49 +08:00
Techflash 7b5dc58140 CPU (Linux): fix CPU detection on some PPC platforms (#1640)
On some PowerPC devices (notably the Nintendo Wii and Nintendo Wii U),
fastfetch detects the CPU incorrectly.  It goes down the code path
of 'detectSocName()', and actually matches the model of the device
itself... as the CPU model name.  This is obviously incorrect, and
leads to reporting such as 'CPU: wii'.  Disable this code path
alltogether on PPC to prevent this, and just let it pull from cpuinfo.
This lets it have correct CPU reporting, such as on the Wii, giving
'CPU: 750CL @ 0.73GHz'.
2025-03-25 03:05:23 -05:00
李通洲 8681d2f74a GPU (Windows): fix code smells 2025-03-25 00:14:03 +08:00
李通洲 2b20ed873c GPU: update JSON result structure; fix segfault and memleaks 2025-03-24 22:56:00 +08:00
李通洲 ae3c15b7fd GPU (Windows): support VMEM type detection via nvapi
Ref #993
2025-03-24 21:43:09 +08:00
李通洲 8dafd8f300 GPU (Windows): rewrite implementation for AMD GPUs using ADL SDK
Detect more information including memory type
2025-03-24 21:43:09 +08:00
李通洲 c9a1765f29 GPU (Windows): support memory type detection for Intel dGPUs 2025-03-24 15:22:34 +08:00
李通洲 cc246ea239 GPU: prepare for memory type & shared memory usage detection 2025-03-24 15:21:14 +08:00
李通洲 0ae5fceb07 GPU (Windows): add display-library for future use 2025-03-23 23:53:01 +08:00
李通洲 6dd18050be IO: don't suppress IO in debug mode 2025-03-23 21:56:32 +08:00
李通洲 9eca6e0b48 Bootmgr: report boot order 2025-03-23 21:30:53 +08:00
李通洲 4d58d1be66 Smbios (OpenBSD): add comments for UEFI systems [ci skip] 2025-03-23 20:30:31 +08:00
Carter Li 6694388969 Logo (Builtin): fix opensuse-tumbleweed_small
Fix #1636
2025-03-23 17:22:02 +08:00
Carter Li f7058cd125 Wifi (Linux): add verbose logs 2025-03-23 17:19:43 +08:00
李通洲 80033b656f Wifi (DragonFly): fix building 2025-03-23 12:23:30 +08:00
李通洲 1c719fa743 Bootmgr (BSD): add support for OpenBSD and NetBSD 2025-03-23 12:08:15 +08:00
李通洲 a9f5722fd9 BIOS (OpenBSD): check bios type 2025-03-23 11:34:02 +08:00
李通洲 0952d7917f Smbios: add verbose debug logs 2025-03-23 11:19:49 +08:00
李通洲 a3f50f32bf Smbios (OpenBSD): add support for legency BIOS 2025-03-23 11:19:49 +08:00
李通洲 ab1bfffbd4 util/debug: add missing headers 2025-03-23 10:52:08 +08:00
李通洲 41d6187f11 Wifi (FreeBSD): use ioctl to improve performance
And support more features
2025-03-23 09:46:44 +08:00
Techflash d4b175b146 Logo (Builtin): Change WiiLinuxNgx to more generic name (#1633)
Wii-Linux-Ngx is no longer the most up to date version of Linux for the Wii.
This change retains the original name for compatibility sake, and because
Neagix's version does indeed still exist.  It moves the ASCII art to a more
generic file path, and introduces 2 new aliases for it: Wii-Linux, and WiiLinux.
2025-03-21 17:21:54 +08:00
Carter Li 8905962389 Packaging: update debian stuff [ci skip] 2025-03-21 11:03:29 +08:00
李通洲 d9d34ccbbb Terminal (macOS): fix Warp Terminal pid detection 2025-03-21 10:08:26 +08:00
李通洲 d21048c165 Presets: update examples/{24,26} [ci skip] 2025-03-21 09:43:06 +08:00
Carter Li 8b0c32a35f Merge pull request #1631 from fastfetch-cli/dev
Release v2.39.1
2025-03-20 23:24:14 +08:00
李通洲 db269d29e8 Release: v2.39.1 2025-03-20 23:16:13 +08:00
李通洲 f9f628eae6 Networking: request HTTP/1.0, as we don't support chunked response
Fix #1629
2025-03-20 23:08:41 +08:00
Carter Li 92e9fbf2eb Packaging: update debian stuff [ci skip] 2025-03-20 10:41:30 +08:00
Carter Li db6e4f4bfc Merge pull request #1625 from fastfetch-cli/dev
Release: v2.39.0
2025-03-20 09:48:26 +08:00
李通洲 b662db452f Packages (Linux): add pkgsrc detection
We will not add pkgsrc detection for macOS unless someone can verify it.

Ref: https://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/sysutils/fastfetch/patches/patch-src_detection_packages_packages__linux.c?rev=1.1;content-type=text%2Fplain
2025-03-19 14:59:59 +08:00
李通洲 0d2ccb5fe5 Logo (Builtin): add NetBSD2
Ref: https://cvsweb.netbsd.org/bsdweb.cgi/pkgsrc/sysutils/fastfetch/patches/patch-src_logo_ascii_netbsd2.txt?rev=1.1;content-type=text%2Fplain
2025-03-19 14:49:49 +08:00
apocelipes d33b5d60b6 Display (Linux): fix the error check for ffReadFileData (#1622) 2025-03-18 19:51:51 +08:00
李通洲 ef5d12395b Release: v2.39.0 2025-03-18 16:25:35 +08:00
李通洲 e18c261054 Networking (FreeBSD): support fast path without TFO enabled 2025-03-18 14:18:53 +08:00
Carter Li 8851821484 Networking: don't enable TFO if server doesn't support it 2025-03-18 10:53:02 +08:00
Carter Li 3489cc8fe8 Networking: don't enable HTTP compression if server doesn't support it 2025-03-18 10:19:32 +08:00
Carter Li 28bc97b92b Networking (Linux): remove unnecessary variables 2025-03-18 09:51:11 +08:00
李通洲 dbc5a7961e Networking (Linux): don't generate SIGPIPE 2025-03-17 23:13:44 +08:00
李通洲 5f43f63990 Networking (Windows): more verbose log 2025-03-17 22:54:47 +08:00
李通洲 b775fe7486 Networking (macOS): support TFO 2025-03-17 15:59:39 +08:00
李通洲 60eaa326a2 Networking (BSD): support TCP_FASTOPEN 2025-03-17 09:07:30 +08:00
李通洲 672d4ad543 Completion (Bash): Use fastfetch --help-raw for auto-completion
Fix #1619
2025-03-16 18:35:50 +08:00
李通洲 96e9e61437 Networking (Windows): print readable error message 2025-03-16 10:38:04 +08:00
李通洲 dbc6f70f19 Networking (Windows): fix libz loading; use TCP_FASTOPEN if available 2025-03-16 10:09:33 +08:00
Carter Li dfc9bc265c Networking: silence compiler warnings 2025-03-16 09:51:50 +08:00
Carter Li 2ce511c4d3 Networking (Linux): handle a case when sendto() reports EINPROGRESS 2025-03-16 09:40:12 +08:00
李通洲 99415a3841 Networking: move files to a sub folder 2025-03-15 23:47:02 +08:00
李通洲 244625d26a Networking (Windows): apply the same optimizations of *nix's 2025-03-15 23:35:58 +08:00
李通洲 840434e709 Netif (Windows): use GetIpForwardTable2 to support IPv6 2025-03-15 22:37:49 +08:00
Carter Li 72afa9ef99 Networking (Linux): improve performance by TFO and response compression 2025-03-15 22:35:11 +08:00
李通洲 7400f14322 Netif (DragonFly): use code of OpenBSD 2025-03-14 23:54:03 +08:00
李通洲 85654316c7 NetIF (OpenBSD): fix default route detection 2025-03-14 22:15:20 +08:00
李通洲 8ecd58dd14 Doc: update changelog [ci skip] 2025-03-14 16:12:16 +08:00
李通洲 65c7f68c31 Wifi (macOS): remove usage of Apple80211
It's no longer useful in Sequoia
2025-03-14 15:53:08 +08:00
李通洲 bf6d0f871a Completions (Bash): remove --lib-*
They are removed long ago
2025-03-14 15:32:22 +08:00
李通洲 3cd7c6c916 OpenGL: drop OSMesa backend
Fix #1618
2025-03-14 15:30:52 +08:00
李通洲 3227e934de Logo (Builtin): add Bredos
Fix #1615
2025-03-14 09:43:16 +08:00
WolfTech Innovations b66a009046 Logo (Builtin): Change FoxOS to WolfOS (#1534)
* Update builtin.c

* Update and rename foxos.txt to wolfos.txt

* Update builtin.c

* Update builtin.c

* Update builtin.c

* Logo (Builtin): move WolfOS to the correct place

* Update wolfos.txt

* Update src/logo/builtin.c

Co-authored-by: Levvie - she/her <11600822+ItzLevvie@users.noreply.github.com>

* Update src/logo/builtin.c

Co-authored-by: Levvie - she/her <11600822+ItzLevvie@users.noreply.github.com>

---------

Co-authored-by: komaru <winbo.yml@proton.me>
Co-authored-by: Levvie - she/her <11600822+ItzLevvie@users.noreply.github.com>
2025-03-11 08:48:39 +08:00
李通洲 6ef4f62d5b Terminal (Windows): detect warp version 2025-03-06 22:11:36 +08:00
李通洲 c038024108 Wifi (macOS): improve performance of SSID detection on Sequoia
Fix #1597
Thanks @torma616 for the information
2025-03-06 16:04:22 +08:00
李通洲 df49a01827 Merge remote-tracking branch 'origin/master' into dev 2025-03-06 15:16:07 +08:00
Carter Li 924c670915 Packaging: update debian stuff [ci skip] 2025-03-05 14:59:16 +08:00
李通洲 be89dff12a Kmod (NetBSD): add __attribute__((__packed__)) to ensure memory layout 2025-03-04 23:23:46 +08:00
李通洲 c1807a1108 CI: remove unnecessary deps 2025-03-04 23:23:46 +08:00
Matheus Castello b569acbb5d Logo (Builtin): Add Common Torizon OS as a variant 2025-03-04 21:57:29 +08:00
李通洲 6e571a3163 Display (Windows): prefer DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO_2 2025-03-04 21:13:48 +08:00
李通洲 01e78e2179 Kmod (NetBSD): add support 2025-03-03 20:27:14 +08:00
809 changed files with 43399 additions and 19617 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
[codespell]
check-filenames =
builtin = clear,rare,usage,informal
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu
+3
View File
@@ -0,0 +1,3 @@
github: LinusDierheimer
ko_fi: carterli
custom: https://paypal.me/zhangsongcui
+2
View File
@@ -36,3 +36,5 @@ body:
required: true
- label: The ASCII art contains color codes, or the color codes are available in `os-release`
required: true
- label: The ASCII art contains no internal paddings (spaces at the start and the end of lines)
required: true
+256 -203
View File
@@ -4,13 +4,16 @@ on:
- push
- pull_request
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
jobs:
spellcheck:
runs-on: ubuntu-latest
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Install codespell
shell: bash
@@ -29,13 +32,13 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: uname -a
run: uname -a
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_XFCONF=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OSMESA=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -58,17 +61,24 @@ jobs:
- name: run tests
run: ctest --output-on-failure
linux-amd64:
name: Linux-amd64
runs-on: ubuntu-20.04
linux-hosts:
name: Linux-${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
permissions:
security-events: write
contents: read
strategy:
matrix:
include:
- arch: amd64
runs-on: ubuntu-22.04
- arch: aarch64
runs-on: ubuntu-22.04-arm
outputs:
ffversion: ${{ steps.ffversion.outputs.ffversion }}
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: uname -a
run: uname -a
@@ -79,26 +89,31 @@ jobs:
- name: cat /proc/cpuinfo
run: cat /proc/cpuinfo
- name: add gcc-13 repo
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev
run: sudo apt-get update && sudo apt-get install -y gcc-13 g++-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libchafa-dev directx-headers-dev rpm ninja-build
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa ddcutil --ignore-dependencies
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick --ignore-dependencies
- name: Initialize CodeQL
if: matrix.arch == 'amd64'
uses: github/codeql-action/init@v3
with:
languages: c
- name: configure project
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: CC=gcc-13 CXX=g++-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: perform CodeQL analysis
if: matrix.arch == 'amd64'
uses: github/codeql-action/analyze@v3
- name: list features
@@ -123,21 +138,33 @@ jobs:
id: ffversion
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
- name: polyfill glibc
run: |
wget https://github.com/CarterLi/polyfill-glibc/releases/download/v0.0.1/polyfill-glibc-${{ matrix.arch }} -O polyfill-glibc
chmod +x polyfill-glibc
strip fastfetch && ./polyfill-glibc fastfetch --target-glibc=2.17
strip flashfetch && ./polyfill-glibc flashfetch --target-glibc=2.17
echo 'set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-polyfilled")' >> CPackConfig.cmake
echo 'set(CPACK_PACKAGE_RELOCATABLE OFF)' >> CPackConfig.cmake
echo 'set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.17)")' >> CPackConfig.cmake
echo 'set(CPACK_RPM_SPEC_MORE_DEFINE "%global __os_install_post %{nil}")' >> CPackConfig.cmake
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-amd64
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
linux-aarch64:
name: Linux-aarch64
runs-on: ubuntu-22.04-arm
linux-i686:
name: Linux-i686
runs-on: ubuntu-22.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: uname -a
run: uname -a
@@ -148,15 +175,29 @@ jobs:
- name: cat /proc/cpuinfo
run: cat /proc/cpuinfo
- name: add gcc-13 repo
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
- name: cmake version
run: cmake --version
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_DIRECTX_HEADERS=Off .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: check deb package
run: dpkg -I fastfetch-*.deb
- name: list features
run: ./fastfetch --list-features
@@ -175,14 +216,10 @@ jobs:
- name: run tests
run: ctest --output-on-failure
- name: get fastfetch version
id: ffversion
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-aarch64
name: fastfetch-linux-i686
path: ./fastfetch-*.*
linux-armv7l:
@@ -193,7 +230,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: run VM
uses: uraimo/run-on-arch-action@v3
@@ -204,12 +241,13 @@ jobs:
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y wget
# CMake installed by apt has bug `list sub-command REMOVE_ITEM requires two or more arguments`
wget --no-check-certificate https://apt.kitware.com/ubuntu/pool/main/c/cmake/{cmake_3.29.2-0kitware1ubuntu20.04.1_armhf.deb,cmake-data_3.29.2-0kitware1ubuntu20.04.1_all.deb}
dpkg -i *.deb
apt-get install -y make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
apt-get update && apt-get install -y software-properties-common ca-certificates gpg curl
add-apt-repository -y ppa:ubuntu-toolchain-r/test
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -232,7 +270,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: run VM
uses: uraimo/run-on-arch-action@v3
@@ -244,8 +282,8 @@ jobs:
run: |
uname -a
apt-get update && apt-get install -y wget
apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -260,27 +298,35 @@ jobs:
name: fastfetch-linux-armv6l
path: ./fastfetch-*.*
linux-riscv64:
name: Linux-riscv64
runs-on: ubuntu-24.04
linux-vms:
name: Linux-${{ matrix.arch }}
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
strategy:
matrix:
include:
- arch: riscv64
- arch: ppc64le
- arch: s390x
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: run VM
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: riscv64
arch: ${{ matrix.arch }}
distro: ubuntu22.04
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libddcutil-dev libchafa-dev libelf-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
apt-get update && apt-get install -y software-properties-common
add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -292,84 +338,14 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-riscv64
path: ./fastfetch-*.*
linux-ppc64le:
name: Linux-ppc64le
runs-on: ubuntu-24.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: ppc64le
distro: ubuntu20.04
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-ppc64le
path: ./fastfetch-*.*
linux-s390x:
name: Linux-s390x
runs-on: ubuntu-24.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: s390x
distro: ubuntu20.04
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-s390x
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
musl-amd64:
name: Musl-amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
- name: setup alpine linux
uses: jirutka/setup-alpine@master
@@ -378,7 +354,7 @@ jobs:
run: |
cat /etc/alpine-release
uname -a
apk add cmake samurai vulkan-loader-dev libxcb-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
shell: alpine.sh --root {0}
- name: build
@@ -403,15 +379,22 @@ jobs:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
macos-universal:
name: macOS-universal
runs-on: macos-latest
macos-hosts:
name: macOS-${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
permissions:
security-events: write
contents: read
strategy:
matrix:
include:
- arch: amd64
runs-on: macos-15-intel
- arch: aarch64
runs-on: macos-latest
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: uname -a
run: uname -a
@@ -421,7 +404,7 @@ jobs:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' .
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -447,7 +430,7 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos-universal
name: fastfetch-macos-${{ matrix.arch }}
path: ./fastfetch-*.*
sunos-amd64:
@@ -455,7 +438,7 @@ jobs:
name: SunOS-amd64
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: run VM
uses: vmactions/omnios-vm@v1
@@ -463,8 +446,9 @@ jobs:
usesh: true
prepare: |
uname -a
pkg install pkg:/package/pkg
pkg update --accept
pkg install gcc13 cmake git pkg-config glib2 dbus sqlite-3 imagemagick
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
@@ -491,7 +475,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: run VM
uses: cross-platform-actions/action@master
@@ -500,11 +484,11 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '14.2'
version: '14.3'
run: |
uname -a
sudo pkg update
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl libosmesa opencl ocl-icd v4l_compat chafa
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -520,41 +504,6 @@ jobs:
name: fastfetch-freebsd-amd64
path: ./fastfetch-*.*
dragonfly-amd64:
name: DragonFly-amd64
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: vmactions/dragonflybsd-vm@v1
with:
usesh: yes
prepare: |
uname -a
pkg update
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl libosmesa opencl ocl-icd v4l_compat chafa libelf
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-dragonfly-amd64
path: ./fastfetch-*.*
openbsd-amd64:
name: OpenBSD-amd64
runs-on: ubuntu-latest
@@ -563,7 +512,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: run VM
uses: cross-platform-actions/action@master
@@ -572,11 +521,12 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '7.6'
version: '7.7'
run: |
uname -a
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa pulseaudio hwdata
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
sudo pkg_add -u
sudo pkg_add -r llvm-19.1.7p3 cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
CC=clang-19 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -599,7 +549,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: run VM
uses: cross-platform-actions/action@master
@@ -611,8 +561,8 @@ jobs:
version: '10.1'
run: |
uname -a
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick pulseaudio opencl-headers ocl-icd
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
@@ -627,40 +577,120 @@ jobs:
name: fastfetch-netbsd-amd64
path: ./fastfetch-*.*
windows-amd64:
name: Windows-amd64
runs-on: windows-latest
dragonfly-amd64:
name: DragonFly-amd64
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: run VM
uses: vmactions/dragonflybsd-vm@v1
with:
usesh: yes
prepare: |
uname -a
pkg update
pkg install -y llvm cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf
run: |
env CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-dragonfly-amd64
path: ./fastfetch-*.*
haiku-amd64:
name: Haiku-amd64
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: run VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
version: 'r1beta5'
architecture: x86-64
cpu_count: 4
shell: bash
run: |
uname -a
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-haiku-amd64
path: ./fastfetch-*.*
windows-hosts:
name: Windows-${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
permissions:
security-events: write
contents: read
strategy:
matrix:
include:
- arch: amd64
runs-on: windows-latest
msystem: CLANG64
msystem-lower: clang64
msys-arch: x86_64
- arch: aarch64
runs-on: windows-11-arm
msystem: CLANGARM64
msystem-lower: clangarm64
msys-arch: aarch64
defaults:
run:
shell: msys2 {0}
steps:
- name: checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: setup-msys2
uses: msys2/setup-msys2@v2
with:
msystem: CLANG64
msystem: ${{ matrix.msystem }}
update: true
install: git mingw-w64-clang-x86_64-7zip mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-vulkan-headers mingw-w64-clang-x86_64-opencl-icd mingw-w64-clang-x86_64-opencl-headers mingw-w64-clang-x86_64-cppwinrt mingw-w64-clang-x86_64-imagemagick
install: git mingw-w64-clang-${{ matrix.msys-arch }}-7zip mingw-w64-clang-${{ matrix.msys-arch }}-cmake mingw-w64-clang-${{ matrix.msys-arch }}-clang mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-loader mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-headers mingw-w64-clang-${{ matrix.msys-arch }}-opencl-icd mingw-w64-clang-${{ matrix.msys-arch }}-opencl-headers mingw-w64-clang-${{ matrix.msys-arch }}-cppwinrt mingw-w64-clang-${{ matrix.msys-arch }}-imagemagick mingw-w64-clang-${{ matrix.msys-arch }}-chafa
- name: print msys version
run: uname -a
- name: configure project
run: env PKG_CONFIG_PATH=/clang64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --verbose -j4
- name: copy necessary dlls
run: cp /clang64/bin/{OpenCL,vulkan-1}.dll .
- name: download amd_ags
run: curl -LO https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/raw/master/ags_lib/lib/amd_ags_x64.dll
run: cp /${{ matrix.msystem-lower }}/bin/{OpenCL,vulkan-1}.dll .
- name: list features
run: ./fastfetch --list-features
@@ -680,38 +710,61 @@ jobs:
- name: run tests
run: ctest --output-on-failure
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-amd64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-amd64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
id: upload-unsigned-artifact
name: upload artifacts for signing
uses: actions/upload-artifact@v4
with:
name: fastfetch-windows-amd64
path: ./fastfetch-windows-amd64.*
name: fastfetch-windows-${{ matrix.arch }}
path: |
*.dll
fastfetch.exe
flashfetch.exe
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
name: submit signing request
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
project-slug: 'fastfetch'
signing-policy-slug: ${{ github.ref == 'refs/heads/master' && 'release-signing' || 'test-signing' }}
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '.'
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload true artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-windows-${{ matrix.arch }}
path: ./fastfetch-windows-${{ matrix.arch }}.*
overwrite: true
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
name: Release
runs-on: ubuntu-latest
needs:
- linux-amd64
- linux-aarch64
- linux-hosts
- linux-i686
- linux-armv7l
- linux-armv6l
- linux-riscv64
- linux-ppc64le
- linux-s390x
- linux-vms
- musl-amd64
- macos-universal
- macos-hosts
- freebsd-amd64
- openbsd-amd64
- netbsd-amd64
- dragonfly-amd64
- sunos-amd64
- windows-amd64
- haiku-amd64
- windows-hosts
permissions:
contents: write
steps:
@@ -722,29 +775,29 @@ jobs:
repository: ${{ github.repository }}
- name: download artifacts
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v4
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v5
- name: create release
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.linux-amd64.outputs.ffversion }}
tag: ${{ needs.linux-hosts.outputs.ffversion }}
commit: ${{ github.sha }}
artifactErrorsFailBuild: true
artifacts: fastfetch-*/fastfetch-*
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details."
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-hosts.outputs.ffversion }}/CHANGELOG.md) for details."
- name: download source tarballs
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
run: |
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-amd64.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-hosts.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
ls fastfetch-*/*
- name: generate release notes
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
run: |
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-hosts.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
echo -e "\n---\n\n<details><summary>SHA256SUMs</summary><br>\n\n\`\`\`" >> fastfetch-release-notes.md
sha256sum fastfetch-*/* >> fastfetch-release-notes.md
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
@@ -753,10 +806,10 @@ jobs:
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
- name: update release body
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.linux-amd64.outputs.ffversion }}
tag: ${{ needs.linux-hosts.outputs.ffversion }}
commit: ${{ github.sha }}
bodyFile: fastfetch-release-notes.md
allowUpdates: true
+653 -2
View File
@@ -1,3 +1,654 @@
# 2.55.0
Changes:
* Commands are now executed in parallel by default to improve performance (#2045, Command)
* This behavior can be disabled in the config file with `"parallel": false` if it causes problems with certain scripts
* Folder/filesystem hiding is moved to the detection stage; hidden entries are no longer probed, improving performance (#2043, Disk)
Features:
* Adds `command.parallel` and `command.useStdErr` config options (Command)
* `parallel`: set to `false` to disable parallel execution (see Changes above)
* `useStdErr`: set to `true` to use stderr output instead of stdout
* Adds the command-line flag `--dynamic-interval <interval-in-ms>` to enable dynamic output auto-refresh (#2041)
* Due to internal limitations, some modules do not support dynamic updates (notably Display and Media)
* Adds support for using the current playing media's cover art as a logo source (Media / Logo)
* Usage: `"logo": { "type": "<image-protocol>", "source": "media-cover" }` in JSON config; or `--<image-protocol> media-cover` in command line
* Supports local sources only
* Adds native GPU detection support on OpenBSD and NetBSD (instead of depending on `libpciaccess`) (GPU)
* No functional changes
* Root privileges are required to access PCI config space on OpenBSD (as always)
* Adds GPU detection support on GNU/Hurd (GPU)
* Requires building with `libpciaccess`
* Shows Debian point release on Raspberry Pi OS (#2032, OS, Linux)
* Adds `Brush` shell version detection (Shell)
* Improves Mac family detection via prefix matching (Host)
Bugfixes:
* Ignores `run-parts` during terminal/shell detection (#2048, Terminal / Shell, Linux)
* Fixes fish version detection when `LC_ALL` is set (#2014, Shell, Linux)
* Hides the module when no desktop icons are found (#2023, Icons, Windows)
* Skips auxiliary display controllers to prevent the module from reporting duplicate entries (#2034, GPU, Linux)
* Refines Apple rpath handling; fixes building for the Homebrew version on macOS (#1998, CMake)
Logos:
* Adds Vincent OS and MacaroniOS
# 2.54.0
Windows binaries in Release page are now signed by SignPath.
Changes:
* Moves macOS and Windows design language detection from the DE module to the Theme module
Features:
* Adds `--json` and `-j` command line flags as a shortcut for `--format json`
* Various improvements to the OS module (OS)
* Displays point releases for Debian
* Displays code names for Ubuntu
* Displays build ID for macOS
* Displays code names for Windows (previously shown in the Kernel module)
* Adds basic support for Wine (Windows)
* Adds basic support for hppa and sh architectures (CPU, Linux)
* Improves T-Head SoC name detection from the device tree (#1997, CPU, Linux)
* Supports glob patterns in `Disk.hideFolders` (Disk)
* For example, `/boot/*` will match both `/boot/efi` and `/boot/firmware`
* Adds brightness-level detection for external monitor support on Intel macOS (Brightness, macOS)
* Adds configurable spacing between icon and text in keys
* `display.key.type: "both-N"` where N is `0-4`
* Useful for non-monospaced Nerd Fonts
* Adds detection support for modern Samsung Exynos SoCs (CPU, Android)
* Adds a new CMake option `-DENABLE_WORDEXP=<ON|OFF>` to enable or disable using `wordexp(3)` for acquiring logo file paths (`logo.source`)
* Enabled by default for compatibility
* Disabling this option reverts to using `glob(3)`, which is less functional but more secure
Bugfixes:
* Avoids integer overflow when calculating swap size (#1988, Swap, Windows)
* Trims whitespace from full user name (Title, macOS)
* Fixes default font size for Ghostty (#1986, TerminalFont, Linux)
* Works around an issue that could report impossibly high memory usage in rare cases (#1988, Memory, Linux)
* Fixes incorrect glibc dependency in polyfilled DEB packages (#1983, Linux)
* Fixes corrupted binaries in polyfilled RPM packages (#1990, Linux)
* Fixes crashes on ancient Android kernels (#1993, Disk, Android)
* Fixes incorrect usage of `glob(3)` (OpenBSD)
* Prefers resolutions reported by RandR mode info, fixing incorrect resolutions on XFCE when DPI scaling is enabled (Display, Linux)
* Various code cleanups and minor fixes
Logos:
* Adds secureblue, PrismLinux, EmperorOS and Zraxyl
* Updates T2
# 2.53.0
Changes:
* JSON property `length` in `Separator` module has been renamed to `times` for clarity (Separator)
Features:
* Adds IPv6 type selection (#1459, LocalIP)
* For example: `{ "type": "localip", "showIpv6": "ula" /* Show ULA only */ }`
* Adds more ARM CPU part IDs (CPU, Linux)
* Improves Ghostty font config parsing with fallback font detection (#1967, TerminalFont)
* Replaces statx(2) call with syscall(2) for better compatibility (Disk, Linux)
* Allows array input for disk folder and filesystem options (Disk)
* For example: `{ "type": "disk", "folders": ["/", "/home"] }`
* Adds support for ignoring input devices by name prefix (#1950, Keyboard / Mouse / Gamepad)
* For example: `{ "type": "keyboard", "ignores": ["Apple ", "Corsair "] }`
* Adds support for (B)SSID detection on macOS Tahoe (Wifi, macOS)
* Please don't expect it to work on later macOS versions
* Improves Ubuntu flavor detection (#1975, OS, Linux)
* Refines ARMv8.4-A detection to require LSE2 (CPU, Windows)
* Detects the latest Dimensity & Snapdragon SoC names (CPU, Android)
Bugfixes:
* Handles zero temperature data (#1960, CPU, Windows)
* Fixes `dlopen libzfs.so failed` error on Proxmox 9 (#1973, Zpool, Linux)
Logos:
* Removes Starry Linux
* Adds TempleOS
* Updates ObsidianOS
# 2.52.0
Changes:
* New optional build dependencies on Android
* main: chafa dbus glib imagemagick libelf libxcb libxrandr pulseaudio zlib
* x11: dconf (Optional)
* Dependency on `libxfconf` is removed. XFCE related detection now uses `libdbus` instead (Linux)
* The default format of `Display` module is updated to `{width}x{height} @ {scale-factor}x in {inch}", {refresh-rate} Hz`
* Replaced scaled resolution with scale factor for shorter texts and avoiding potential confusion.
Bugfixes:
* Fixes linking on 32-bit Android (#1939)
* Skips network interfaces without IPs unless MAC address is requested (#1949, LocalIP)
* Fixes unexpected padding when setting `logo.width` with chafa logos (#1947, Logo)
* Regression from v2.51.0
* Improves Wallpaper detection on XFCE4 (Wallpaper, Linux)
* Ignores process `Relay(xxx)` when detecting terminal on WSL2 (Terminal, Linux)
Features:
* Enables X11-related info (i.e., WM/DE) detection on Android (Global, Android)
* This requires many dependencies. See above.
* Adds scale factors detection for X11 (Display, Linux)
* X11 doesn't natively report scale factor as Wayland does. Instead, Fastfetch tries to detect `Xft.dpi` (DPI used by X FreeType for scaling fonts), which is usually set by the WM when DPI scaling is enabled.
* It's not always accurate. For example, XFCE4 has a separate config for text scaling, which is unaffected by the global DPI scaling setting.
* Adds `display.fraction.trailingZeros: [always|never]` option for fraction formatting
* The default value of `display.fraction.ndigits` is changed from `-1` (unlimited) to `2` for usability.
* Used for displaying scale factor in Display module mentioned above, alongside other places for printing raw fraction numbers.
* Informs users that module-specific CLI options are no longer supported and provide guidance for transitioning to JSON config
* Adds CPU name detection support for IA64 (CPU, Linux)
* Support Btrfs allocation profile detection (#1941, Btrfs, Linux)
# 2.51.1
Bugfixes:
* Fix building on macOS 14 or older; no functional changes (CPU, macOS)
# 2.51.0
Changes:
* Fastfetch now requires [yyjson 0.12](https://github.com/ibireme/yyjson/releases/tag/0.12.0) to build when using `-DENABLE_SYSTEM_YYJSON=ON`.
* The Disk module no longer shows hyperlink mountpoints by default, which cause issues on some real consoles (Disk)
* Instead, the custom key for the Disk module now supports `{mountpoint-link}` and `{name-link}` to show hyperlinks for mountpoints and names. For example, `{ "type": "disk", "key": "Disk ({mountpoint-link})" }` can be used to restore the old behavior.
Features:
* Adds `succeeded` module condition to JSONC config. When set to `false`, the module will only run if the last module failed (#1908)
* Useful for displaying fallback placeholders when a module fails. For example:
```jsonc
{
"host",
// If fastfetch fails to detect host info, display "DIY PC" instead
{
"type": "custom",
"condition": {
"succeeded": false
},
"key": "Host",
"format": "DIY PC"
}
}
```
* By upgrading to yyjson 0.12, fastfetch now adds [JSON5](https://json5.org/) format support for configuration files (#1907)
* [JSON5](https://json5.org/) is a superset of JSONC that allows unquoted keys, single quotes, multi-line strings, etc., and is fully compatible with JSONC and strict JSON.
* To use JSON5, simply name your config file with a `.json5` extension. The `.jsonc` extension is still supported and used as the default extension for better IDE syntax highlighting support.
* Fastfetch has been ported to [`GNU/Hurd`](https://www.gnu.org/software/hurd/) (#1895)
* Thanks to the efforts of @yelninei!
* Built-in logos now honor `logo.width` (#1905)
* When its value is larger than the actual logo width, the logo will be padded with spaces to the right
* Adds Trinity DE version detection (#1917, DE, Linux)
* Adds formatted free and available disk size fields (#1929, Disk)
* `{size-free}`: free size of the disk
* `{size-available}`: available size of the disk
* See [askubuntu.com](https://askubuntu.com/questions/249387/df-h-used-space-avail-free-space-is-less-than-the-total-size-of-home) for the difference between free and available size
* Adds [x86_64 micro-architecture level](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels) detection (#1928, CPU)
* Useful when installing software that requires or is optimized for specific CPU features. E.g., [CachyOS](https://wiki.cachyos.org/features/optimized_repos/)
* Exposed via `{march}` in custom format
* Adds [Aarch64 micro-architecture level](https://en.wikipedia.org/wiki/AArch64#Profiles) detection (CPU)
* Supported on Linux (including Android), macOS and Windows
* This is not fully accurate because there are many optional features across different levels, and not all levels are detectable.
* Exposed via `{march}` in custom format.
* Adds shepherd detection support (InitSystem, Linux)
Bugfixes:
* Refines GPU detection logic to correctly handle virtual devices (#1920, GPU, Windows)
* Fixes possible default route detection failure when the route table is very large (#1919, LocalIP, Linux)
* Fastfetch now correctly parses `hwdata/pci.ids` files alongside `pciids/pci.ids` on FreeBSD when detecting GPU names (#1924, GPU, FreeBSD)
* Fixes twin WM detection (#1917, WM, Linux)
* Various fixes for Android support
* Corrects WM name for Android (WM, Android)
* Fixes battery temperature detection when running in ADB (Battery, Android)
* Adds CPU and GPU temperature detection support (CPU, Android)
Logos:
* Adds AerynOS
# 2.50.2
Bugfixes:
* Fixes linglong package detection V2 (#1903, Packages, Linux)
* Fixes building with `-DENABLE_SYSTEM_YYJSON=ON` (#1904)
* Fixes `showMac` does not honor `defaultRouteOnly` (#1902, LocalIP, Linux)
* Fixes failing to acquire default route on Linux in certain cases (#1902, LocalIP, Linux)
# 2.50.1
Bugfixes:
* Fixes percentage bar not displaying correctly in certain cases
* Fixes linglong package detection on Debian 13 (#1899, Packages, Linux)
# 2.50.0
Changes:
* Keys in JSON configuration files are now case-sensitive, as stated in v2.49.0.
* This is a breaking change, but it should not affect most users as long as your config file passes JSON schema validation.
* All module config flags have been removed, as stated in v2.49.0.
* To configure modules via the command line, use: `echo '{"modules": [{"type":"custom","format":"Hello Fastfetch!"}]}' | fastfetch -c -`.
* The percent bar config `display.bar.*` options have been replaced with a more organized, nested object structure.
* `display.bar.charElapsed` has been renamed to `display.bar.char.elapsed`.
* `display.bar.charTotal` has been renamed to `display.bar.char.total`.
* `display.bar.borderLeft` has been renamed to `display.bar.border.left`.
* `display.bar.borderRight` has been renamed to `display.bar.border.right`.
* The undocumented flag `--load-config` has been removed.
* Use `--config` or `-c` instead.
* Flashfetch, a simplified fastfetch variant that used a hardcoded module list with direct function calls to reduce startup overhead, has been changed to a version that aims to match neofetch's behavior as closely as possible, for demonstration purposes.
* Flashfetch is intended to be built from source (like [st](https://st.suckless.org/)). We do not provide prebuilt binaries in distributions.
Features:
* Added support for reading JSON config from stdin using `--config -` or `-c -`.
* Added `display.bar.border.{leftElapsed,rightElapsed}` for using the border as part of the bar content. (#1875)
* `display.bar.border: null` has been added as a shorthand to disable bar borders.
* Added `display.bar.color.{elapsed,total,border}` to customize the color of the elapsed, total, and border sections of the percent bar.
* `display.bar.color: null` has been added as a shorthand to disable bar colors.
* Improved Bedrock Linux detection (#1881, OS / Disk, Linux)
* Added the command flag `--gen-config-full`, which generates a JSON config file containing all optional module options.
* Improved the default IP address display when `localip.showAllIPs` is not set (LocalIP)
* For IPv4, the preferred source address (if detected) is shown.
* For IPv6, the first GUA or ULA that is not deprecated or temporary is shown.
* Added support for interface speed detection on SunOS (LocalIP, SunOS)
* Added detection support for Xlibre (#1888, WM, Linux)
* Improved the accuracy of color detection (Cursor, macOS)
* Improved the proformance of `Nix` package manager detection on macOS by porting optimizations form Linux port (#1893, Packages, macOS)
Bugfixes:
* Fixed custom object inheriting a key from the previous custom object if the key is blank (#1477)
* Fixed a possible segfault when parsing color strings in the JSON config (#1878)
* Fixed GPU driver detection when DRM is used (GPU, FreeBSD)
* Fixed default route detection on DragonFly BSD (LocalIP, DFBSD)
* Fixed lliurex detection (#1882, OS, Linux)
* Fixed compatibility with `-ffast-math` (#1894)
* Fixed physical GPU sometimes being ignored (#1896, GPU, Windows)
Logos:
* Added ObsidianOS (#1890)
# 2.49.0
Deprecation Notice:
* In fastfetch v2, the JSONC configuration format has been introduced, while command line configuration flags are kept for compatibility. Although they have the same effects, they use two different code paths, and as the number of flags grows, the codebase is becoming increasingly difficult to maintain.
* Removal of module config flags is planned for **v2.50.0**, which will also fix a long-standing issue #1477.
* Removal of most other config flags is also planned for later versions.
* Keys of JSON configuration files will be all case-sensitive. Currently they are inconsistent. Planned for **v2.50.0**.
Changes:
* Due to more restrictive permissions in macOS Tahoe, SSID detection on macOS 26+ requires root privileges. `<redacted>` will be displayed otherwise.
Features:
* Improve `nouveau` driver support for `--gpu-driver-specific` (GPU, Linux)
* VRAM size detection
* GPU temperature detection
* Core count detection (when available)
* Improve Scoop package manager detection (Packages, Windows)
* Support [`scoop-global`](https://github.com/ScoopInstaller/Install?tab=readme-ov-file#advanced-installation)
* Read Scoop's config file to find the installation path of Scoop
* Improve ARM SoC detection (CPU, Android)
* Make SoC detection more lenient. Higher chance to match at the cost of accuracy.
* Add more Snapdragon SoC names
* Support labwc WM version detection, used for XFCE4 on Wayland (WM, Linux)
* Improve accuracy of GPU temperature detection for Intel dedicated GPUs on Windows (GPU, Windows)
* Parse unicode escaped strings generated by qt5ct (#1864, Font, Linux)
* Add `--{duration,percent,size,freq,temp}-space-before-unit [always|never]` options to add a space before the unit when printing duration, percent, size, frequency and temperature values
* Add `--duration-abbreviation` to abbreviate duration values in custom format
* For example: `1 day, 2 hours, 3 mins` will be displayed as `1d 2h 3m`
* Add `--percent-width` to pad the percent value with spaces to a fixed width
* For example: `--percent-width 3` will display ` 50%` instead of `50%`; useful for aligning percent values in custom format
Bugfixes:
* Improve accuracy of Flatpak count detection (#1856, Packages, Linux)
* Remove qi package manager support (#1858, Packages, Linux)
* Fix LocalIP module on Windows (LocalIP, Windows)
* Fix default route detection when multiple network interfaces are connected
* Fix link speed calculation
* Fix interface status when the interface is up but not connected (Wifi, Linux)
* Fix variable names in custom format (#1861)
* `full-path` to `path` (Editor)
* `session` to `session-name` (Users)
* `name` to `project-name` (Version)
* Fix wrong /s assignment in custom format (#1871, DiskIO)
Logos:
* Add `Aeon`
* Remove `Evolinx`
# 2.48.1
Features:
* Add support for detecting Openbox WM version (WM, Linux)
* Improve reliability of child process spawning on Windows (Windows)
* Add a new option `--packages-combined`, which combines related package managers into single counts (#1851, Packages)
* For example: if you have both `flatpak-system` and `flatpak-user` packages installed, they will be combined into a single `flatpak` count with `--packages-combined` enabled.
* Add `modules[n].condition` to conditionally enable modules on different platforms
* Useful when sharing configuration files across platforms
* For example:
```jsonc
{
"type": "custom",
"format": "This string will be printed on Intel macOS only",
"condition": {
"system": "macOS", // Can be an array, optional
"arch": "x86_64" // Can be an array, optional too
}
}
```
Bugfixes:
* Revert the change of `posix_spawn` in v2.48.0 for Android and OpenBSD (Android / OpenBSD)
* Fix completion for Android 7 (Required by Termux)
# 2.48.0
Features:
* Add support for detecting Fedora variants (#1830, OS, Linux)
* Currently supported variants: CoreOS, Kinoite, Sericea, Silverblue
* Optimize GPU detection on Windows when `--gpu-driver-specific` is not used (GPU, Windows)
* Improve accuracy of GPU type detection. Previously it was guessed based on the dedicated vmem size, which causes issues on newer AMD integrated GPUs such as 9000 HX and AI 9 HX series. Supported on Windows 8.1 or later.
* Add support for generic frequency detection of GPU 3D engine on Windows 11 22H2 or later.
* Improve performance. GPU temperature detection is significantly improved when `--gpu-driver-specific` is not used.
* Improve performance and security when spawning child processes by replacing `fork-exec` with `posix_spawn` (*nix)
* Improve accuracy of sound device detection on macOS (Sound, macOS)
* Trim leading and trailing whitespaces in disk serial numbers (PhysicalDisk)
* Add `/etc/profiles/per-user` detection for Nix user packages (#1782, Packages, Linux)
* Introduce `years` (whole years as integer), `days-of-year` (days since the last anniversary) and `years-fraction` (years as fraction, e.g. 1.5 means 1 year and 6 months) formatting placeholder to `Disk` (since disk creation), `Users` (since user login) and `Uptime` (since system boot) modules
* For example: `fastfetch -s disk --disk-key 'OS Installation' --disk-format '{years} years {days-of-year} days'`
* Add `--fraction-ndigits` option to specify the number of digits after the decimal point when displaying ordinary fractional values
* Typically used with `{years-fraction}` above
* This option does not affect percentage values, sizes, etc, which are controlled by individual options.
Bugfixes:
* Fix compilation issues when not using `-DBINARY_LINK_TYPE=dlopen`
* Regression from v2.47.0
* Note: this option was added for debugging purposes only and is not recommended for production use
* Replace `MTLDevice::hasUnifiedMemory` with `MTLDevice::location` for GPU type Detection (GPU, macOS)
* This should resolve the issue where discrete GPUs were detected as integrated GPUs on Intel MacBooks with multi-GPU configurations.
* Prevent text files from being loaded as image files (#1843, Logo)
Logos:
* Add Minimal System
* Add AxOS
* Rename Ada to Xray OS
# 2.47.0
Features:
* Various improvements for Solaris / OpenIndiana support
* Support BIOS (UEFI or legacy) type detection (BIOS)
* Support physical disk detection (PhysicalDisk)
* Remove leading `-` from login shells (Shell)
* Improve GPU detection performance (GPU)
* Drop `libpciaccess` dependency
* Use native API to detect sound devices (Sound)
* Drop `PulseAudio` dependency
* Improve DietPi OS and Raspberry Pi OS detection (#1816, OS, Linux)
* Force reporting version 26 on macOS Tahoe (OS, macOS)
* Append version string to Ubuntu variants (OS, Linux)
* Improve performance of media detection for macOS 15.4+ (Media, macOS)
* Increase `PROC_FILE_BUFFSIZ` to avoid possible short reads (Linux)
* Fix potential bugs in `DiskIO`, `NetIO` and `CPUUsage` modules
* Improve accuracy of CPU usage calculations by including interrupt and softirq times (CPUUsage, Linux / *BSD)
* Ignore `init` and `systemd` processes when detecting terminals (Terminal, Linux)
* Improve accuracy of CPU usage detection on Windows 10+ with perflib, which matches values reported by Task Manager (CPUUsage, Windows)
Bugfixes:
* Fix `pci.ids` file location (#1819, GPU, OpenBSD)
* Fix compiling on FreeBSD when `libdrm` support is disabled (#1820, GPU, FreeBSD)
Logos:
* Improve visibility on white-background terminals for some logos by replacing white with the default foreground color
* According to Wikipedia, the default foreground color is implementation-defined. It's usually black for white themes and white for dark themes. However, some terminals, notably Konsole with the default theme, use a different color, which may cause issues with some logos.
* Add Xubuntu
# 2.46.0
Features:
* Support Rio terminal font detection (#1789, TerminalFont, Linux)
* Support GPU detection by DRM on FreeBSD (GPU, FreeBSD)
* Enable by `--gpu-detection-method auto`
* Require proper DRM drivers installed and loaded
* Support PowerPC CPU detection on NetBSD (#1802, CPU, NetBSD)
* Support Aerospace WM detection (#1796, WM, macOS)
* Improve Raspberry Pi OS for RPI5 detection (#1773, OS, Linux)
* Support Linux Binary Compatibility detection on FreeBSD (#1786, Host, Linux)
* Use `board-id` as board name if available (Board, macOS)
* Intel only
* Support shared VRAM usage detection for AMD GPUs (GPU, Linux)
* Use `perflib.h` instead of `pdh.h` for CPU temperature querying to get rid of `pdh.dll` dependency (#1787, CPU, Windows)
* Support GPU info detection for old ATI radeon driver (#1810, GPU, Linux)
* Add macOS 26 Tahoe support (macOS)
* Report macOS 26 code name (OS)
* Report Liquid Glass DE on macOS 26+ (DE)
* Detect Metal 4 support (GPU)
Bugfixes:
* Fix packages counting by ignoring hidden folders (Packages, OpenBSD)
* Fix Hyprland version detection (WM, FreeBSD)
* Don't show `Please insert a disk into drive D:` error dialogs (#1805, Disk, Windows)
* Hide `/boot/firmware` by default (Disk, Linux)
Logos:
* Rename Hydra Framework to HydraPwk (#1812)
* Add AnushOS (#1806)
* Add HarmonyOS (#1804)
* Add GhostFreak (#1801)
* Add TrueNAS Scale (#1795)
* Add Fedora2_small (#1785)
* Add xenia_old; update colors of xenia (#1797)
* Improve colors of bedrock_small (#1790)
* Add Kalpa Desktop (#1807)
# 2.45.0
Features:
* Support OnePlus marketing name detection (#1768, Host, Android)
* Recognize additional GPU vendors (GPU, Linux)
* Support CTWM, FVWM and I3 window manager version detection (WM)
* Support KDE version detection on *BSD (DE, FreeBSD)
* Support `"logo": { "type": "command-raw" }` to run a command and display its output as logo (#1780, Logo)
* Useful for displaying custom logos generated by other programs such as `pokeget`: `{ "type": "command-raw", "source": "pokeget random --hide-name" }`
* Supported in JSONC config file only. `pokeget random --hide-name | fastfetch --file-raw -` should be used in shell.
* Acquire SMBIOS information on DragonFly BSD from `/dev/mem`; legacy BIOS only (PhysicalMemory, DragonFly)
* Support swap usage detection on DragonFly BSD (Swap, DragonFly)
* Support `--swap-separate` to display detailed swap devices on separate lines (Swap)
Bugfixes
* Fix MacBook Air model name (#1779, Host, macOS)
* Don't ignore sshfs mountpoints (#1776, Disk, Linux / FreeBSD)
* Fix dnf package count detection (#1777, Packages, Linux)
Logos:
* Add Starry Linux (#1771)
* Add rhel_small (#1774)
* Update color palette of voidlinux (#1775)
* Add void2
* Update Xenia Linux (#1783)
# 2.44.0
Features:
* Add option `--disk-hide-folders` and `--disk-hide-fs` to hide specific mountpoints and filesystems in Disk module (Disk)
* `--disk-hide-folders` defaults to `/efi:/boot:/boot/efi` on Linux and *BSD. Previously these EFI-related folders were hardcoded to be hidden on Linux.
Bugfixes:
* Fix Apple Terminal compatibility with `--stat` (macOS, #1755)
* Ignore `/usr/bin/script` when detecting shell and terminal (Terminal / Shell, #1761)
* Fix compatibility with KDE Plasma 6.4 which is in beta currently (Display, Linux, #1765)
Logos:
* Add Kylin (#1760)
* Add UBLinux (#1764)
# 2.43.0
Features:
* Support physical core count and package count detection on Solaris (CPU, SunOS)
* Improve physical core count detection on FreeBSD (CPU, FreeBSD)
* Add option to hide unknown GPUs (GPU)
* Detect VRAM type of AMD GPUs on Linux (GPU, Linux)
* Support playing media detection on macOS 15.4 (#1737, Media, macOS)
* Whether it works on newer versions is unknown
* Detect player name for Windows UMP apps (Media, Windows)
Bugfixes:
* Fix disk usage detection on 32-bit Linux (#1734, Disk, Linux)
* Fix compiling on Asahi Linux (GPU, Linux)
* Fix duplicated playback status (Media, Linux)
* Don't show 255 in custom format when muted on macOS (#1750, Sound, macOS)
* Remove shared memory detection for AMD GPUs, which doesn't work as expected (GPU, Windows)
Logos:
* new AthenaOS
* add Hydra Framework
# 2.42.0
Changes:
* Normalize the module name `Bios` to `BIOS` (#1721)
* No configuration file changes are required because fastfetch parses module names case-insensitively.
Bugfixes:
* Disable disk type detection for virtual disks (PhysicalDisk, Linux, #1669)
* Fix incorrect CPU temperature reporting (CPU, OpenBSD)
* Fix setting `logo.chafa.symbols` in JSON configuration (Logo, #1709)
* Fix non-normalized time display (Uptime, #1720)
* Miscellaneous minor fixes
Features:
* Add CPU temperature detection support (CPU, SunOS)
* Improve CPU frequency detection (CPU, NetBSD)
* Add Wi-Fi detection support (Wifi, NetBSD)
* Add Webcam detection support (Camera, OpenBSD)
* Requires root privileges
Logos:
* Remove GoralixOS logo (#1699)
* Add Aurora logo (#1700)
* Add Codex Linux logo (#1701)
# 2.41.0
Changes:
* Due to [the deprecation](https://github.com/actions/runner-images/issues/11101), Linux x86_64 binaries are now built with Ubuntu 22.04 (Glibc 2.35, Debian 12)
* You can always build fastfetch yourself on your own. Please don't report bugs related to this change.
Features:
* Support physical core count detection on non-x86 platforms (CPU, Linux / FreeBSD)
* Support CPU frequency detection on PPC64 (CPU, FreeBSD)
* Support soar packages count detection (Packages, Linux)
* Support `~` path expanding on Windows (Logo, Windows)
* Support retrieving full user name (Title)
* Exposed with `--title-format '{full-user-name}'`
* Improve CPU (thermal zone) temperature detection on Windows (CPU, Windows)
* Administrator privileges are no longer needed
* Support base Wifi info detection on OpenBSD (Wifi, OpenBSD)
* To be tested
* Support GPU temperature detection for Intel dGPU on Linux (GPU, Linux)
* To be tested
* Add new ARM CPU part numbers (CPU, Linux)
* Add base implementation of Bluetooth device detection (Bluetooth, NetBSD, #1690)
* Some small improvements
Logo:
* Add anduinos
* Add 2 more Alpine logos
# 2.40.4
Bugfixes:
* Fix loading presets config on Windows (Windows, #1682)
* Regression of v2.40.0
* Remove the prefix `v` of Hyprland version on Arch Linux (WM, Linux)
# 2.40.3
Bugfixes:
* Fix loading example configs from presets directory (#1672)
* Regression of v2.40.2
* Mark kitty image protocol support for warp terminal on macOS too (Logo)
# 2.40.2
Changes:
* Since v2.40.0, we've been loading config files from the directory where the fastfetch binary is located. However, this approach may lead to loading unexpected files. For example, `fastfetch -c groups` would attempt to load `/usr/bin/groups`. Therefore, we now enforce the `.jsonc` extension when loading config files. Examples:
1. `-c filename`: loads `filename.jsonc`
2. `-c filename.jsonc`: loads `filename.jsonc`
3. `-c filename.json`: loads `filename.json` and enforces strict JSON syntax (no comments or trailing commas)
4. `-c filename.ext`: loads `filename.ext.jsonc` (`.jsonc` extension is enforced)
Features:
* Mark kitty image protocol support for warp terminal (Logo)
* Documentation improvements
# 2.40.1
Bugfixes:
* Fix compiling error on old intel platform (TPM, macOS)
* Fix `--file-raw -` no longer working (Logo, #1659)
* Regression of v2.40.0
# 2.40.0
Changes:
* In `key-format` of `LocalIP` module, `{name}` has been renamed to `{ifname}` for consistency (LocalIP, #1639)
Features:
* Support Warp Terminal font detection (TerminalFont, Windows)
* Support more AMD GPU information using ADL SDK, including memory type detection (GPU, Windows)
* Support Intel dGPU memory type detection (GPU, Windows)
* Support Nvidia VMEM type detection via NVAPI (GPU, Windows, #993)
* Support Boot manager detection for OpenBSD and NetBSD (Bootmgr, OpenBSD / NetBSD)
* Use `SystemConfiguration` for DNS entries detection (DNS, macOS)
* Add `systemd-resolved` support for DNS module (DNS, Linux, #1646)
* Improve performance and accuracy of Wifi detection on FreeBSD using ioctl (Wifi, FreeBSD)
* Support remaining time reporting for batteries on NetBSD (Battery, NetBSD)
* Add new Mac models support (Host, macOS)
* Load config from fastfetch binary path with `--config` option (#1649)
* Support TPM detection on macOS (TPM, macOS)
* Support IPv6 client address report (Users, Linux / Windows)
* Support default route detection for IPv6 (LocalIP, Linux)
* Round seconds to the nearest minute to match the behavior of `uptime` command (Uptime)
Bugfixes:
* Fix `outputColor` not working when `length` is set in Separator module (#1644)
* Fix CPU detection on PowerPC platforms (#1640, CPU, Linux)
* Fix battery manufacture date detection (Battery, macOS)
* Fix battery critical state detection (Battery, Linux)
* Fix Warp Terminal PID detection (Terminal, macOS)
* Remove disk creation time detection support on SunOS as ctim is file status change timestamp, not creation time (Disk, SunOS)
* Fall back to KDGKBINFO if `usbhid` fails (Keyboard, FreeBSD)
* Fix multiple paging file support (Swap, Windows)
* Fix memleaks, code smells in multiple modules
* Fix boot time calculation on NetBSD (Uptime, NetBSD)
* Temporarily fix Hyprland version detection (WM, Linux, #1657)
Logo:
* Fix opensuse-tumbleweed_small (#1636)
* Change WiiLinuxNgx to more generic name with aliases Wii-Linux and WiiLinux (#1633)
* Change name of Xray-OS to Ada (#1651)
* Change Nexa Linux logo (#1653)
# 2.39.1
Bugfixes:
* Fix a regression that PublicIP detection fails randomly (PublicIP, #1629)
# 2.39.0
Changes:
* OSMesa backend for OpenGL detection is removed (#1618)
* Fastfetch no longer tries to use the private framework `Apple80211` to acquire SSID for Wifi module, which is only useful for macOS Sonoma (Wifi, macOS)
Features:
* Improve accuracy of HDR support on Windows 11 24H2 (Display, Windows)
* Improve performance of SSID detection on macOS Sequoia (Wifi, macOS, #1597)
* Support warp terminal version detection on Windows (Terminal, Windows)
* Support default route detection on OpenBSD & DragonFly BSD (LocalIP, OpenBSD / DragonFly)
* Improve bash completion script
* Improve performance of networking (PublicIP / Weather)
* Support pkgsrc package manager detection on Linux (Packages, Linux)
Logo:
* Add Common Torizon OS
* Change FoxOS to WolfOS
* Add Bredos
* Add NetBSD2
# 2.38.0
Bugfixes:
@@ -310,7 +961,7 @@ Features:
* Support tilix version detection (Terminal, Linux)
* Support percent type config in module level. Example:
```json
```jsonc
{
"type": "memory",
"percent": {
@@ -750,7 +1401,7 @@ Bugfixes:
* Fix some presets
* Better detection for XTerm terminal fonts (#1095, TerminalFont, Linux)
* Remove debug output (#1097, Windows)
* Fix command line option `--gpu-hide-type` doesn't work (#1098, GPU)
* Fix flag `--gpu-hide-type` doesn't work (#1098, GPU)
* Fix wrong date on Raspbian 10 (#1108, DateTime, Linux)
* Use `brightness` instead of `actuall_brightness` when detecting current brightness level (Brightness, Linux)
* Ref: https://bugzilla.kernel.org/show_bug.cgi?id=203905
+271 -134
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.38.0
VERSION 2.55.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -9,6 +9,17 @@ project(fastfetch
set(PROJECT_LICENSE "MIT license")
if(DEFINED CMAKE_SYSTEM_PROCESSOR_OVERRIDE) # Used by github actions for i686 build
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR_OVERRIDE} CACHE INTERNAL "")
endif()
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" CMAKE_SYSTEM_PROCESSOR)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
endif()
message(STATUS "Build for system processor: ${CMAKE_SYSTEM_PROCESSOR}")
###################
# Target Platform #
###################
@@ -32,6 +43,8 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")
set(SunOS TRUE CACHE BOOL "..." FORCE)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Haiku")
set(Haiku TRUE CACHE BOOL "..." FORCE)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU")
set(GNU TRUE CACHE BOOL "..." FORCE)
elseif(NOT APPLE AND NOT WIN32)
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
endif()
@@ -56,35 +69,33 @@ include(CheckIncludeFile)
include(CMakeDependentOption)
cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku" OFF)
cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD" OFF)
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" OFF)
cmake_dependent_option(ENABLE_XFCONF "Enable libxfconf-0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_SQLITE3 "Enable sqlite3" ON "LINUX OR FreeBSD OR APPLE OR OpenBSD OR NetBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_RPM "Enable rpm" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR WIN32 OR SunOS OR Haiku" OFF)
cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR SunOS" OFF)
cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR GNU" OFF)
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD OR GNU" OFF)
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_SQLITE3 "Enable sqlite3" ON "LINUX OR FreeBSD OR APPLE OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_RPM "Enable rpm" ON "LINUX OR GNU" OFF)
cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR ANDROID OR WIN32 OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_CHAFA "Enable chafa" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF)
cmake_dependent_option(ENABLE_ZLIB "Enable zlib" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF)
cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR WIN32 OR SunOS OR Haiku" OFF)
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS" OFF)
cmake_dependent_option(ENABLE_OSMESA "Enable osmesa" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" OFF)
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku" OFF)
cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR WIN32 OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR SunOS" OFF)
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR ANDROID OR GNU" OFF)
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku" OFF)
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
cmake_dependent_option(ENABLE_LIBZFS "Enable libzfs" ON "LINUX OR FreeBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD OR SunOS" OFF)
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "GNU" OFF)
option(ENABLE_ZLIB "Enable zlib" ON)
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
option(ENABLE_LTO "Enable link-time optimization in release mode if supported" ON)
@@ -95,6 +106,7 @@ option(IS_MUSL "Build with musl libc" OFF) # Used by Github Actions
option(INSTALL_LICENSE "Install license into /usr/share/licenses" ON)
option(ENABLE_EMBEDDED_PCIIDS "Embed pci.ids into fastfetch, requires `python`" OFF)
option(ENABLE_EMBEDDED_AMDGPUIDS "Embed amdgpu.ids into fastfetch, requires `python`" OFF)
option(ENABLE_WORDEXP "Enable using of wordexp(3) if available, instead of glob(3)" ON)
set(BINARY_LINK_TYPE_OPTIONS dlopen dynamic static)
set(BINARY_LINK_TYPE dlopen CACHE STRING "How to link fastfetch")
@@ -103,7 +115,7 @@ if(NOT BINARY_LINK_TYPE IN_LIST BINARY_LINK_TYPE_OPTIONS)
message(FATAL_ERROR "BINARY_LINK_TYPE must be one of ${BINARY_LINK_TYPE_OPTIONS}")
endif()
set(PACKAGE_MANAGERS AM APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SORCERY WINGET XBPS)
set(PACKAGE_MANAGERS AM APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SOAR SORCERY WINGET XBPS)
foreach(package_manager ${PACKAGE_MANAGERS})
if(package_manager STREQUAL "WINGET")
option(PACKAGES_DISABLE_${package_manager} "Disable ${package_manager} package manager detection by default" ON)
@@ -326,9 +338,6 @@ endif()
fastfetch_encode_c_string("${DATATEXT_JSON_HELP}" DATATEXT_JSON_HELP)
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
fastfetch_load_text(src/data/help_footer.txt DATATEXT_HELP_FOOTER)
fastfetch_load_text(src/data/help_color.txt DATATEXT_HELP_COLOR)
fastfetch_load_text(src/data/help_format.txt DATATEXT_HELP_FORMAT)
configure_file(src/fastfetch_config.h.in fastfetch_config.h @ONLY)
configure_file(src/fastfetch_datatext.h.in fastfetch_datatext.h @ONLY)
@@ -340,13 +349,12 @@ endif()
# Ascii image data #
####################
file(GLOB LOGO_FILES "src/logo/ascii/*.txt")
file(GLOB LOGO_FILES CONFIGURE_DEPENDS "src/logo/ascii/*.txt")
set(LOGO_BUILTIN_H "#pragma once\n#pragma GCC diagnostic ignored \"-Wtrigraphs\"\n\n")
foreach(file ${LOGO_FILES})
fastfetch_load_text("${file}" content)
get_filename_component(file "${file}" NAME_WE)
string(TOUPPER "${file}" file)
string(REGEX REPLACE "\\$\\{c([0-9]+)\\}" "$\\1" content "${content}")
set(LOGO_BUILTIN_H "${LOGO_BUILTIN_H}#define FASTFETCH_DATATEXT_LOGO_${file} ${content}\n")
endforeach()
file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
@@ -356,26 +364,32 @@ file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
#######################
set(LIBFASTFETCH_SRC
src/common/percent.c
src/common/commandoption.c
src/common/duration.c
src/common/font.c
src/common/format.c
src/common/frequency.c
src/common/init.c
src/common/jsonconfig.c
src/common/library.c
src/common/modules.c
src/common/netif/netif.c
src/common/networking/networking_common.c
src/common/option.c
src/common/parsing.c
src/common/percent.c
src/common/printing.c
src/common/properties.c
src/common/settings.c
src/common/size.c
src/common/temps.c
src/common/time.c
src/detection/bluetoothradio/bluetoothradio.c
src/detection/bootmgr/bootmgr.c
src/detection/chassis/chassis.c
src/detection/cpu/cpu.c
src/detection/cpuusage/cpuusage.c
src/detection/command/command.c
src/detection/disk/disk.c
src/detection/diskio/diskio.c
src/detection/displayserver/displayserver.c
@@ -475,7 +489,6 @@ set(LIBFASTFETCH_SRC
src/modules/wmtheme/wmtheme.c
src/modules/zpool/zpool.c
src/options/display.c
src/options/modules.c
src/options/logo.c
src/options/general.c
src/util/edidHelper.c
@@ -493,7 +506,7 @@ if(LINUX)
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_linux.c
src/common/networking_linux.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/detection/battery/battery_linux.c
src/detection/bios/bios_linux.c
@@ -514,6 +527,7 @@ if(LINUX)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_linux.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -528,6 +542,7 @@ if(LINUX)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_linux.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_linux.c
@@ -548,6 +563,7 @@ if(LINUX)
src/detection/opengl/opengl_linux.c
src/detection/os/os_linux.c
src/detection/packages/packages_linux.c
src/detection/packages/packages_nix.c
src/detection/poweradapter/poweradapter_linux.c
src/detection/processes/processes_linux.c
src/detection/gtk_qt/qt.c
@@ -572,9 +588,10 @@ if(LINUX)
)
elseif(ANDROID)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_linux.c
src/common/networking_linux.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/detection/battery/battery_android.c
src/detection/bios/bios_android.c
@@ -587,7 +604,7 @@ elseif(ANDROID)
src/detection/chassis/chassis_nosupport.c
src/detection/cpu/cpu_linux.c
src/detection/cpucache/cpucache_linux.c
src/detection/cursor/cursor_nosupport.c
src/detection/cursor/cursor_linux.c
src/detection/cpuusage/cpuusage_linux.c
src/detection/disk/disk_linux.c
src/detection/dns/dns_linux.c
@@ -595,10 +612,16 @@ elseif(ANDROID)
src/detection/physicalmemory/physicalmemory_nosupport.c
src/detection/diskio/diskio_linux.c
src/detection/displayserver/displayserver_android.c
src/detection/font/font_nosupport.c
src/detection/gpu/gpu_nosupport.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/gtk_qt/gtk.c
src/detection/gtk_qt/qt.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_android.c
src/detection/host/host_android.c
src/detection/icons/icons_nosupport.c
src/detection/icons/icons_linux.c
src/detection/initsystem/initsystem_linux.c
src/detection/keyboard/keyboard_nosupport.c
src/detection/libc/libc_android.c
@@ -607,29 +630,31 @@ elseif(ANDROID)
src/detection/locale/locale_linux.c
src/detection/localip/localip_linux.c
src/detection/gamepad/gamepad_nosupport.c
src/detection/media/media_nosupport.c
src/detection/media/media_linux.c
src/detection/memory/memory_linux.c
src/detection/mouse/mouse_nosupport.c
src/detection/netio/netio_linux.c
src/detection/opengl/opengl_linux.c
src/detection/os/os_android.c
src/detection/packages/packages_linux.c
src/detection/packages/packages_nix.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_linux.c
src/detection/sound/sound_nosupport.c
src/detection/sound/sound_linux.c
src/detection/swap/swap_linux.c
src/detection/terminalfont/terminalfont_android.c
src/detection/terminalfont/terminalfont_linux.c
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_nosupport.c
src/detection/theme/theme_linux.c
src/detection/tpm/tpm_nosupport.c
src/detection/uptime/uptime_linux.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_nosupport.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_android.c
src/detection/wm/wm_nosupport.c
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_nosupport.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_android.c
src/detection/zpool/zpool_nosupport.c
src/util/platform/FFPlatform_unix.c
@@ -640,7 +665,7 @@ elseif(FreeBSD)
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_bsd.c
src/common/networking_linux.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/detection/battery/battery_bsd.c
@@ -661,6 +686,7 @@ elseif(FreeBSD)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_bsd.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -675,6 +701,7 @@ elseif(FreeBSD)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_bsd.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_bsd.c
@@ -708,8 +735,7 @@ elseif(FreeBSD)
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_bsd.c
src/detection/wm/wm_nosupport.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
@@ -720,10 +746,12 @@ elseif(FreeBSD)
if(DragonFly)
list(APPEND LIBFASTFETCH_SRC
src/detection/bluetooth/bluetooth_nosupport.c
src/detection/wifi/wifi_nosupport.c
)
else()
list(APPEND LIBFASTFETCH_SRC
src/detection/bluetooth/bluetooth_bsd.c
src/detection/wifi/wifi_bsd.c
)
endif()
elseif(NetBSD)
@@ -731,15 +759,15 @@ elseif(NetBSD)
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_bsd.c
src/common/networking_linux.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/detection/battery/battery_nbsd.c
src/detection/bios/bios_nbsd.c
src/detection/bluetooth/bluetooth_nosupport.c
src/detection/bluetooth/bluetooth_bsd.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/board/board_nbsd.c
src/detection/bootmgr/bootmgr_nosupport.c
src/detection/bootmgr/bootmgr_bsd.c
src/detection/brightness/brightness_nbsd.c
src/detection/btrfs/btrfs_nosupport.c
src/detection/chassis/chassis_nbsd.c
@@ -753,6 +781,7 @@ elseif(NetBSD)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_nbsd.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -766,7 +795,7 @@ elseif(NetBSD)
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_general.c
src/detection/gpu/gpu_nbsd.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_nbsd.c
@@ -785,7 +814,7 @@ elseif(NetBSD)
src/detection/netio/netio_bsd.c
src/detection/opengl/opengl_linux.c
src/detection/os/os_nbsd.c
src/detection/packages/packages_obsd.c
src/detection/packages/packages_nbsd.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_nbsd.c
src/detection/gtk_qt/qt.c
@@ -799,8 +828,8 @@ elseif(NetBSD)
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wm/wm_nosupport.c
src/detection/wifi/wifi_nbsd.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
@@ -813,28 +842,29 @@ elseif(OpenBSD)
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_bsd.c
src/common/networking_linux.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/detection/battery/battery_obsd.c
src/detection/bios/bios_nosupport.c
src/detection/bios/bios_windows.c
src/detection/bluetooth/bluetooth_nosupport.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/board/board_nosupport.c
src/detection/bootmgr/bootmgr_nosupport.c
src/detection/board/board_windows.c
src/detection/bootmgr/bootmgr_bsd.c
src/detection/brightness/brightness_obsd.c
src/detection/btrfs/btrfs_nosupport.c
src/detection/chassis/chassis_nosupport.c
src/detection/chassis/chassis_windows.c
src/detection/cpu/cpu_obsd.c
src/detection/cpucache/cpucache_nosupport.c
src/detection/cpucache/cpucache_shared.c
src/detection/cpuusage/cpuusage_bsd.c
src/detection/cursor/cursor_linux.c
src/detection/disk/disk_bsd.c
src/detection/dns/dns_linux.c
src/detection/physicaldisk/physicaldisk_nosupport.c
src/detection/physicalmemory/physicalmemory_nosupport.c
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_obsd.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -849,7 +879,7 @@ elseif(OpenBSD)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_pci.c
src/detection/gpu/gpu_general.c
src/detection/gpu/gpu_obsd.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_obsd.c
src/detection/lm/lm_nosupport.c
@@ -881,20 +911,21 @@ elseif(OpenBSD)
src/detection/uptime/uptime_bsd.c
src/detection/users/users_obsd.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wm/wm_nosupport.c
src/detection/wifi/wifi_obsd.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
src/detection/zpool/zpool_nosupport.c
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
src/util/smbiosHelper.c
)
elseif(APPLE)
list(APPEND LIBFASTFETCH_SRC
src/common/io/io_unix.c
src/common/netif/netif_bsd.c
src/common/networking_linux.c
src/common/netif/netif_apple.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/detection/battery/battery_apple.c
@@ -911,7 +942,7 @@ elseif(APPLE)
src/detection/cpuusage/cpuusage_apple.c
src/detection/cursor/cursor_apple.m
src/detection/disk/disk_bsd.c
src/detection/dns/dns_linux.c
src/detection/dns/dns_apple.c
src/detection/physicaldisk/physicaldisk_apple.c
src/detection/physicalmemory/physicalmemory_apple.m
src/detection/diskio/diskio_apple.c
@@ -937,6 +968,7 @@ elseif(APPLE)
src/detection/opengl/opengl_apple.c
src/detection/os/os_apple.m
src/detection/packages/packages_apple.c
src/detection/packages/packages_nix.c
src/detection/poweradapter/poweradapter_apple.c
src/detection/processes/processes_bsd.c
src/detection/sound/sound_apple.c
@@ -944,8 +976,8 @@ elseif(APPLE)
src/detection/terminalfont/terminalfont_apple.m
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_nosupport.c
src/detection/tpm/tpm_nosupport.c
src/detection/theme/theme_apple.c
src/detection/tpm/tpm_apple.c
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_apple.m
@@ -965,7 +997,7 @@ elseif(WIN32)
list(APPEND LIBFASTFETCH_SRC
src/common/io/io_windows.c
src/common/netif/netif_windows.c
src/common/networking_windows.c
src/common/networking/networking_windows.c
src/common/processing_windows.c
src/detection/battery/battery_windows.c
src/detection/bios/bios_windows.c
@@ -978,7 +1010,6 @@ elseif(WIN32)
src/detection/btrfs/btrfs_nosupport.c
src/detection/chassis/chassis_windows.c
src/detection/cpu/cpu_windows.c
src/detection/cpu/cpu_windows.cpp
src/detection/cpucache/cpucache_windows.c
src/detection/cpuusage/cpuusage_windows.c
src/detection/cursor/cursor_windows.c
@@ -1006,7 +1037,7 @@ elseif(WIN32)
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/netio/netio_windows.c
src/detection/opengl/opengl_windows.c
src/detection/os/os_windows.c
src/detection/os/os_windows.cpp
src/detection/packages/packages_windows.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_windows.c
@@ -1015,7 +1046,7 @@ elseif(WIN32)
src/detection/terminalfont/terminalfont_windows.c
src/detection/terminalshell/terminalshell_windows.c
src/detection/terminalsize/terminalsize_windows.c
src/detection/theme/theme_nosupport.c
src/detection/theme/theme_windows.c
src/detection/tpm/tpm_windows.c
src/detection/uptime/uptime_windows.c
src/detection/users/users_windows.c
@@ -1034,13 +1065,14 @@ elseif(WIN32)
src/util/windows/version.c
src/util/platform/FFPlatform_windows.c
src/util/binary_windows.c
src/util/debug_windows.c
)
elseif(SunOS)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_bsd.c
src/common/networking_linux.c
src/common/netif/netif_apple.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/detection/battery/battery_nosupport.c
src/detection/bios/bios_windows.c
@@ -1057,10 +1089,11 @@ elseif(SunOS)
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/disk/disk_sunos.c
src/detection/dns/dns_linux.c
src/detection/physicaldisk/physicaldisk_nosupport.c
src/detection/physicaldisk/physicaldisk_sunos.c
src/detection/physicalmemory/physicalmemory_linux.c
src/detection/diskio/diskio_sunos.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
@@ -1097,7 +1130,7 @@ elseif(SunOS)
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_linux.c
src/detection/gtk_qt/qt.c
src/detection/sound/sound_linux.c
src/detection/sound/sound_sunos.c
src/detection/swap/swap_sunos.c
src/detection/terminalfont/terminalfont_linux.c
src/detection/terminalshell/terminalshell_linux.c
@@ -1121,7 +1154,7 @@ elseif(Haiku)
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_haiku.c
src/common/networking_linux.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/detection/battery/battery_haiku.c
src/detection/bios/bios_windows.c
@@ -1186,6 +1219,85 @@ elseif(Haiku)
src/util/binary_linux.c
src/util/haiku/version.cpp
)
elseif(GNU)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_gnu.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/detection/battery/battery_nosupport.c
src/detection/bios/bios_nosupport.c
src/detection/board/board_nosupport.c
src/detection/bootmgr/bootmgr_nosupport.c
src/detection/brightness/brightness_nosupport.c
src/detection/btrfs/btrfs_nosupport.c
src/detection/chassis/chassis_nosupport.c
src/detection/cpu/cpu_linux.c
src/detection/cpucache/cpucache_nosupport.c
src/detection/cpuusage/cpuusage_linux.c
src/detection/cursor/cursor_linux.c
src/detection/bluetooth/bluetooth_linux.c
src/detection/bluetoothradio/bluetoothradio_linux.c
src/detection/disk/disk_linux.c
src/detection/dns/dns_linux.c
src/detection/physicaldisk/physicaldisk_nosupport.c
src/detection/physicalmemory/physicalmemory_nosupport.c
src/detection/diskio/diskio_nosupport.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_general.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_nosupport.c
src/detection/icons/icons_linux.c
src/detection/initsystem/initsystem_linux.c
src/detection/keyboard/keyboard_nosupport.c
src/detection/libc/libc_linux.c
src/detection/lm/lm_linux.c
src/detection/loadavg/loadavg_linux.c
src/detection/locale/locale_linux.c
src/detection/localip/localip_linux.c
src/detection/gamepad/gamepad_nosupport.c
src/detection/media/media_linux.c
src/detection/memory/memory_linux.c
src/detection/mouse/mouse_nosupport.c
src/detection/netio/netio_nosupport.c
src/detection/opengl/opengl_linux.c
src/detection/os/os_linux.c
src/detection/packages/packages_linux.c
src/detection/packages/packages_nix.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_linux.c
src/detection/gtk_qt/qt.c
src/detection/sound/sound_linux.c
src/detection/swap/swap_linux.c
src/detection/terminalfont/terminalfont_linux.c
src/detection/terminalshell/terminalshell_linux.c
src/detection/terminalsize/terminalsize_linux.c
src/detection/theme/theme_linux.c
src/detection/tpm/tpm_nosupport.c
src/detection/uptime/uptime_linux.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wm/wm_linux.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_nosupport.c
src/detection/zpool/zpool_nosupport.c
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
)
endif()
if(ENABLE_DIRECTX_HEADERS)
@@ -1205,10 +1317,7 @@ endif()
include(CheckFunctionExists)
check_function_exists(wcwidth HAVE_WCWIDTH)
if(NOT HAVE_WCWIDTH)
list(APPEND LIBFASTFETCH_SRC src/3rdparty/mk_wcwidch/wcwidth.c)
endif()
if(LINUX)
check_function_exists(statx HAVE_STATX)
list(APPEND LIBFASTFETCH_SRC src/util/wcwidth.c)
endif()
if(NOT WIN32)
check_function_exists(pipe2 HAVE_PIPE2)
@@ -1232,15 +1341,15 @@ add_library(libfastfetch OBJECT
)
if(yyjson_FOUND)
target_compile_definitions(libfastfetch PUBLIC FF_USE_SYSTEM_YYJSON)
target_compile_definitions(libfastfetch PUBLIC FF_USE_SYSTEM_YYJSON=1)
target_link_libraries(libfastfetch PUBLIC yyjson::yyjson)
# `target_link_libraries(yyjson::yyjson)` sets rpath implicitly
else()
# Used for dlopen finding dylibs installed by homebrew
# `/opt/homebrew/lib` is not on in dlopen search path by default
if(APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/opt/homebrew/lib -Wl,-rpath,/usr/local/lib")
endif()
endif()
# Used for dlopen finding dylibs installed by homebrew
# `/opt/homebrew/lib` is not on in dlopen search path by default
if(APPLE AND NOT BINARY_LINK_TYPE STREQUAL "dlopen")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/opt/homebrew/lib -Wl,-rpath,/usr/local/lib")
endif()
if(ANDROID)
@@ -1309,6 +1418,10 @@ elseif(NetBSD)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/usr/X11R7/lib -Wl,-rpath,/usr/pkg/lib") # ditto
elseif(Haiku)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE)
elseif(GNU)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE)
# On Hurd PATH_MAX is not defined. Set an arbitrary limit as workaround.
target_compile_definitions(libfastfetch PUBLIC PATH_MAX=4096)
endif()
if(FreeBSD OR OpenBSD OR NetBSD)
@@ -1321,10 +1434,6 @@ if(FreeBSD OR OpenBSD OR NetBSD)
unset(CMAKE_REQUIRED_DEFINITIONS)
endif()
if(HAVE_STATX)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_STATX)
endif()
if(HAVE_WCWIDTH)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_WCWIDTH)
endif()
@@ -1435,10 +1544,6 @@ ff_lib_enable(DBUS
"dbus-1"
"DBus"
)
ff_lib_enable(XFCONF
"libxfconf-0"
"XFConf"
)
ff_lib_enable(SQLITE3
"sqlite3"
"SQLite3"
@@ -1478,10 +1583,6 @@ else()
"GL"
)
endif()
ff_lib_enable(OSMESA
"osmesa"
"OSMesa"
)
ff_lib_enable(OPENCL
"OpenCL"
"OpenCL"
@@ -1575,7 +1676,6 @@ elseif(APPLE)
PRIVATE "-F /System/Library/PrivateFrameworks"
PRIVATE "-weak_framework DisplayServices"
PRIVATE "-weak_framework MediaRemote"
PRIVATE "-weak_framework Apple80211"
)
elseif(WIN32)
target_link_libraries(libfastfetch
@@ -1587,14 +1687,19 @@ elseif(WIN32)
PRIVATE "ws2_32"
PRIVATE "ntdll"
PRIVATE "version"
PRIVATE "setupapi"
PRIVATE "hid"
PRIVATE "wtsapi32"
PRIVATE "imagehlp"
PRIVATE "cfgmgr32"
PRIVATE "winbrand"
PRIVATE "propsys"
PRIVATE "secur32"
)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
# WoA only works on Windows 10 or higher
target_link_libraries(libfastfetch
PRIVATE "mincore"
)
endif()
elseif(FreeBSD)
target_link_libraries(libfastfetch
PRIVATE "m"
@@ -1618,6 +1723,7 @@ elseif(OpenBSD)
)
elseif(NetBSD)
target_link_libraries(libfastfetch
PRIVATE "bluetooth"
PRIVATE "m"
PRIVATE "prop"
)
@@ -1629,19 +1735,30 @@ elseif(SunOS)
PRIVATE "proc"
PRIVATE "zfs"
PRIVATE "nvpair"
PRIVATE "devinfo"
)
elseif(GNU)
target_link_libraries(libfastfetch
PRIVATE "m"
)
elseif(ANDROID)
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
if(HAVE_LIBANDROID_WORDEXP_STATIC)
target_link_libraries(libfastfetch
PRIVATE -l:libandroid-wordexp.a
)
else()
CHECK_LIBRARY_EXISTS(android-wordexp wordexp "" HAVE_LIBANDROID_WORDEXP)
if(HAVE_LIBANDROID_WORDEXP)
target_link_libraries(libfastfetch
PRIVATE "m"
)
if(ENABLE_WORDEXP)
# https://github.com/termux/termux-packages/pull/7056
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
if(HAVE_LIBANDROID_WORDEXP_STATIC)
target_link_libraries(libfastfetch
PRIVATE android-wordexp
PRIVATE -l:libandroid-wordexp.a
)
else()
CHECK_LIBRARY_EXISTS(android-wordexp wordexp "" HAVE_LIBANDROID_WORDEXP)
if(HAVE_LIBANDROID_WORDEXP)
target_link_libraries(libfastfetch
PRIVATE android-wordexp
)
endif()
endif()
endif()
elseif(Haiku)
@@ -1703,13 +1820,17 @@ if(NOT WIN32)
if(HAVE_UTMPX)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_UTMPX=1)
endif()
CHECK_INCLUDE_FILE("wordexp.h" HAVE_WORDEXP)
if(HAVE_WORDEXP)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WORDEXP=1)
if(ENABLE_WORDEXP)
CHECK_INCLUDE_FILE("wordexp.h" HAVE_WORDEXP)
if(HAVE_WORDEXP)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WORDEXP=1)
message(STATUS "wordexp.h found, wordexp support enabled")
else()
set(ENABLE_WORDEXP OFF)
endif()
endif()
CHECK_INCLUDE_FILE("glob.h" HAVE_GLOB)
if(HAVE_GLOB)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GLOB=1)
if(NOT ENABLE_WORDEXP)
message(STATUS "wordexp.h not found or disabled, glob used instead")
endif()
if(ENABLE_THREADS AND CMAKE_USE_PTHREADS_INIT)
CHECK_INCLUDE_FILE("pthread_np.h" HAVE_PTHREAD_NP)
@@ -1831,10 +1952,26 @@ if (BUILD_TESTS)
PRIVATE libfastfetch
)
add_executable(fastfetch-test-color
tests/color.c
)
target_link_libraries(fastfetch-test-color
PRIVATE libfastfetch
)
add_executable(fastfetch-test-duration
tests/duration.c
)
target_link_libraries(fastfetch-test-duration
PRIVATE libfastfetch
)
enable_testing()
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
add_test(NAME test-list COMMAND fastfetch-test-list)
add_test(NAME test-format COMMAND fastfetch-test-format)
add_test(NAME test-color COMMAND fastfetch-test-color)
add_test(NAME test-duration COMMAND fastfetch-test-duration)
endif()
##################
@@ -1903,16 +2040,11 @@ install(
set(CPACK_GENERATOR "TGZ;ZIP")
if(APPLE)
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-universal" CPACK_PACKAGE_FILE_NAME)
else() # We don't use this in Windows
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
endif()
if(IS_MUSL)
string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
else()
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
endif()
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) # use macos instead of darwin
elseif(IS_MUSL)
string(TOLOWER "${CMAKE_PROJECT_NAME}-musl-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
else()
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
endif()
if(LINUX)
@@ -1938,17 +2070,22 @@ if(LINUX)
endif()
endif()
find_program(HAVE_RPMBUILD "rpmbuild")
if(HAVE_RPMBUILD)
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
if(NOT IS_MUSL)
find_program(HAVE_RPMBUILD "rpmbuild")
if(HAVE_RPMBUILD)
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
endif()
endif()
elseif(FreeBSD)
set(CPACK_FREEBSD_PACKAGE_LICENSE "MIT")
set(CPACK_GENERATOR "${CPACK_GENERATOR};FREEBSD")
endif()
set(CPACK_SET_DESTDIR ON)
set(CPACK_PACKAGE_CONTACT "Linus Dierheimer <Linus@Dierheimer.de>")
set(CPACK_PACKAGE_CONTACT "Carter Li <zhangsongcui@live.cn>")
set(CPACK_PACKAGE_DESCRIPTION "\
fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way. \
It is written mostly in C to achieve much better performance.\
+75
View File
@@ -0,0 +1,75 @@
# Fastfetch
Fastfetch 是一款类似 neofetch 的系统信息展示工具,主要用 C 编写,强调性能和可定制性。支持 Linux、macOS、Windows 7+、Android、FreeBSD、OpenBSD、NetBSD、DragonFly、Haiku、SunOS。
示例配置见 presets/examples,更多截图与平台说明见 Wiki。
## 安装
Linux(部分):
- Debian 13+ / Ubuntu: apt install fastfetch
- Arch: pacman -S fastfetch
- Fedora: dnf install fastfetch
- openSUSE: zypper install fastfetch
- Linuxbrewbrew install fastfetch
- 各发行版打包状态:https://repology.org/project/fastfetch/versions
macOS
- Homebrewbrew install fastfetch
- MacPortssudo port install fastfetch
Windows
- scoop install fastfetch
- choco install fastfetch
- winget install fastfetch
- MSYS2pacman -S mingw-w64-<subsystem>-<arch>-fastfetch
BSD
- FreeBSDpkg install fastfetch
- NetBSDpkgin in fastfetch
- OpenBSDpkg_add fastfetch
AndroidTermux):
- pkg install fastfetch
Nightly 构建:
- https://nightly.link/fastfetch-cli/fastfetch/workflows/ci/dev?preview
## 源码构建
基本上是 `cmake . && make`。详见 Wikihttps://github.com/fastfetch-cli/fastfetch/wiki/Building
## 使用
- 默认运行:`fastfetch`
- 查看所有可用模块示例:`fastfetch -c all.jsonc`
- 以 JSON 输出指定模块:`fastfetch -s <module1>[:<module2>] --format json`
- 完整命令行帮助:`fastfetch --help`
- 生成最小配置:`fastfetch --gen-config [</path/to/config.jsonc>]`
- 生成完整配置:`fastfetch --gen-config-full`
- 请使用支持 JSON schema 的编辑器(如 VSCode)编辑配置文件!
- 如果你连接 Github 有网络困难(智能提示不生效),可将配置文件中的 `$schema` 的值替换为 `https://gitee.com/carterl/fastfetch/raw/dev/doc/json_schema.json`
## 定制
- 配置使用 JSONC,语法与选项见 Wikihttps://github.com/fastfetch-cli/fastfetch/wiki/Configuration
- 预设示例位于 presets,可用 `-c <filename>` 加载
- Logo 选项与图像显示见文档:https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options
- 模块格式化(示例,仅显示 GPU 名称):
```jsonc
{
"modules": [
{ "type": "gpu", "format": "{name}" }
]
}
```
详见:https://github.com/fastfetch-cli/fastfetch/wiki/Format-String-Guide
## 反馈与支持
- 使用问题:Discussions https://github.com/fastfetch-cli/fastfetch/discussions
- 疑似缺陷:Issues https://github.com/fastfetch-cli/fastfetch/issues(请填写模版)
## 赞助
<img src="https://github.com/user-attachments/assets/a36a6501-e8b0-4a10-9061-b9206d12ffba" width="220">
+116 -50
View File
@@ -10,8 +10,10 @@
[![GitHub release (with filter)](https://img.shields.io/github/v/release/fastfetch-cli/fastfetch?logo=github)](https://github.com/fastfetch-cli/fastfetch/releases)
[![latest packaged version(s)](https://repology.org/badge/latest-versions/fastfetch.svg)](https://repology.org/project/fastfetch/versions)
[![Packaging status](https://repology.org/badge/tiny-repos/fastfetch.svg)](https://repology.org/project/fastfetch/versions)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/fastfetch-cli/fastfetch)
[![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-red)](README-cn.md)
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it prettily. It is written mainly in C, with performance and customizability in mind. Currently, Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS are supported.
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and SunOS.
<img src="screenshots/example1.png" width="49%" align="left" />
<img src="https://upload.wikimedia.org/wikipedia/commons/2/24/Transparent_Square_Tiles_Texture.png" width="49%" height="16px" align="left" />
@@ -21,19 +23,20 @@ Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for
<img src="screenshots/example3.png" width="48%" align="top" />
<img src="screenshots/example5.png" height="15%" align="top" />
According configuration files for examples are located [here](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets/examples).
There are [screenshots on different platforms](https://github.com/fastfetch-cli/fastfetch/wiki).
## Installation
### Linux
Some distros package an outdated fastfetch version. Older versions receive no support, so please try always to use the latest version.
Some distributions package outdated versions of fastfetch. Older versions receive no support, so please always try to use the latest version.
<a href="https://repology.org/project/fastfetch/versions">
<img src="https://repology.org/badge/vertical-allrepos/fastfetch.svg?columns=2" alt="Packaging status" align="right">
</a>
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (for Ubuntu 22.04 or newer)
* Debian: `apt install fastfetch` (for Debian 13 or newer)
* Debian / Ubuntu: Download `fastfetch-linux-<proper architecture>.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and double-click it (for Ubuntu 20.04 or newer and Debian 11 or newer).
* Arch Linux: `pacman -S fastfetch`
@@ -49,13 +52,13 @@ Some distros package an outdated fastfetch version. Older versions receive no su
* Void Linux: `xbps-install fastfetch`
* Venom Linux: `scratch install fastfetch`
You may need `sudo`, `doas` or `sup` to run these commands.
You may need `sudo`, `doas`, or `sup` to run these commands.
If fastfetch is not packaged for your distro or an outdated version is packaged, [linuxbrew](https://brew.sh/) is a good alternative: `brew install fastfetch`
If fastfetch is not packaged for your distribution or an outdated version is packaged, [linuxbrew](https://brew.sh/) is a good alternative: `brew install fastfetch`
### macOS
* [HomeBrew](https://formulae.brew.sh/formula/fastfetch#default): `brew install fastfetch`
* [Homebrew](https://formulae.brew.sh/formula/fastfetch#default): `brew install fastfetch`
* [MacPorts](https://ports.macports.org/port/fastfetch/): `sudo port install fastfetch`
### Windows
@@ -67,9 +70,12 @@ If fastfetch is not packaged for your distro or an outdated version is packaged,
You may also download the program directly from [the GitHub releases page](https://github.com/fastfetch-cli/fastfetch/releases/latest) in the form of an archive file.
### FreeBSD
### BSD systems
* `pkg install fastfetch`
* FreeBSD: `pkg install fastfetch`
* NetBSD: `pkgin in fastfetch`
* OpenBSD: `pkg_add fastfetch` (Snapshots only)
* DragonFly BSD: `pkg install fastfetch` (Snapshots only)
### Android (Termux)
@@ -81,50 +87,55 @@ You may also download the program directly from [the GitHub releases page](https
## Build from source
See Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
## Usage
* Run it with default configuration: `fastfetch`
* Run it with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) and find what interests you: `fastfetch -c all.jsonc`
* Find all data that fastfetch detects: `fastfetch -s <module> --format json`
* Run with default configuration: `fastfetch`
* Run with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) to find what interests you: `fastfetch -c all.jsonc`
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
* Display help messages: `fastfetch --help`
* Generate config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
* Generate a minimal config file: `fastfetch [-s <module1>[:<module2>]] --gen-config [</path/to/config.jsonc>]`
* Use: `--gen-config-full` to generate a full config file with all optional options
## Customization
Fastfetch uses the JSONC (or JSON with comments) for configuration. [See Wiki for detail](https://github.com/fastfetch-cli/fastfetch/wiki/Configuration). There are some premade config files in [`presets`](presets), including the ones used for the screenshots above. You can load them using `-c <filename>`. Those files can serve as examples of the configuration syntax.
Fastfetch uses JSONC (JSON with comments) for configuration. [See the Wiki for details](https://github.com/fastfetch-cli/fastfetch/wiki/Configuration). There are some premade config files in the [`presets`](presets) directory, including those used for the screenshots above. You can load them using `-c <filename>`. These files can serve as examples of the configuration syntax.
Logos can also be heavily customized; see the [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for more information.
### WARNING
Fastfetch supports a `Command` module that can run arbitrary shell commands. If you copy-paste a config file from an untrusted source, it may contain malicious commands that can harm your system or compromise your privacy. Please always review the config file before using it.
## FAQ
### Q: Neofetch is good enough. Why do I need fastfetch?
1. Fastfetch is actively maintained.
2. Fastfetch is faster. As the name suggests.
3. Fastfetch has a greater number of features, though by default fastfetch only has a few modules enabled; use `fastfetch -c all` to find what you want.
2. Fastfetch is faster, as the name suggests.
3. Fastfetch has a greater number of features, though by default it only has a few modules enabled; use `fastfetch -c all` to discover what you want.
4. Fastfetch is more configurable. You can find more information in the Wiki: <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration>.
5. Fastfetch is more polished. For example, neofetch prints `555 MiB` in the Memory module and `23 G` in the Disk module, whereas fastfetch prints `555.00 MiB` and `22.97 GiB` respectively.
6. Fastfetch is more accurate. For example, [neofetch never actually supports the Wayland protocol](https://github.com/dylanaraps/neofetch/pull/2395).
### Q: Fastfetch shows my local IP address. It leaks my privacy!
### Q: Fastfetch shows my local IP address. Does it leak my privacy?
A local IP (10.x.x.x, 172.x.x.x, 192.168.x.x) has nothing to do with privacy. It only makes sense if you are on the same network, for example, if you connect to the same Wi-Fi network.
A local IP address (10.x.x.x, 172.x.x.x, 192.168.x.x) has nothing to do with privacy. It only has meaning if you are on the same network, for example, if you connect to the same Wi-Fi network.
Actually the `Local IP` module is the most useful module for me personally. I (@CarterLi) have several VMs installed to test fastfetch and often need to SSH into them. I have fastfetch running on shell startup and I never need to type `ip addr` manually.
Actually, the `Local IP` module is the most useful module for me personally. I (@CarterLi) have several VMs installed to test fastfetch and often need to SSH into them. With fastfetch running on shell startup, I never need to type `ip addr` manually.
If you really don't like it, you can disable the `Local IP` module in `config.jsonc`.
### Q: Where is the config file? I can't find it.
`Fastfetch` does not generate config file automatically. You can use `fastfetch --gen-config` to generate one. The config file will be saved in `~/.config/fastfetch/config.jsonc` by default. See [Wiki for detail](https://github.com/fastfetch-cli/fastfetch/wiki/Configuration).
Fastfetch does not generate a config file automatically. You can use `fastfetch --gen-config` to generate one. The config file will be saved in `~/.config/fastfetch/config.jsonc` by default. See the [Wiki for details](https://github.com/fastfetch-cli/fastfetch/wiki/Configuration).
### Q: The configuration is so complex. Where is the documentation?
Fastfetch uses JSON (with comments) for configuration. I suggest you use an IDE with JSON schema support (like VSCode) to edit it.
Fastfetch uses JSON (with comments) for configuration. I suggest using an IDE with JSON schema support (like VSCode) to edit it.
Alternatively, you can refer to the presets in [`presets` directory](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets).
Alternatively, you can refer to the presets in the [`presets` directory](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets).
The **correct** way to edit the configuration:
@@ -134,32 +145,32 @@ This is an example that [changes size prefix from MiB / GiB to MB / GB](https://
### Q: I WANT THE DOCUMENTATION!
[Here is the documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Json-Schema). It is generated from [JSON schema](https://github.com/fastfetch-cli/fastfetch/blob/dev/doc/json_schema.json) but you won't like it.
[Here is the documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Json-Schema). It is generated from the [JSON schema](https://github.com/fastfetch-cli/fastfetch/blob/dev/doc/json_schema.json), but you might not find it very user-friendly.
### Q: How can I customize the module output?
Fastfetch uses `format` to generate output. For example, to make the `GPU` module show only the GPU name (leaving other information undisplayed), you can use
Fastfetch uses `format` to generate output. For example, to make the `GPU` module show only the GPU name (leaving other information undisplayed), you can use:
```jsonc
{
"modules": [
{
"type": "gpu",
"format": "{name}" // See `fastfetch -h gpu-format` for detail
"format": "{name}" // See `fastfetch -h gpu-format` for details
}
]
}
```
. . which is equivalent to `fastfetch -s gpu --gpu-format '{name}'`
...which is equivalent to `fastfetch -s gpu --gpu-format '{name}'`
See `fastfetch -h format` for information on basic usage. For module specific formattion, see `fastfetch -h <module>-format`
See `fastfetch -h format` for information on basic usage. For module-specific formatting, see `fastfetch -h <module>-format`
### Q: I have my own ascii-art / image file. How can I show it with fastfetch?
### Q: I have my own ASCII art / image file. How can I show it with fastfetch?
Try `fastfetch -l /path/to/logo`. See [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for detail.
Try `fastfetch -l /path/to/logo`. See the [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for details.
If you just want to display distro name in [FIGlet text](https://github.com/pwaller/pyfiglet):
If you just want to display the distro name in [FIGlet text](https://github.com/pwaller/pyfiglet):
```bash
# install pyfiglet and jq first
@@ -168,32 +179,32 @@ pyfiglet -s -f small_slant $(fastfetch -s os --format json | jq -r '.[0].result.
![image](https://github.com/fastfetch-cli/fastfetch/assets/6134068/6466524e-ab8c-484f-848d-eec7ddeb7df2)
### Q: My image logo behaves weird. How can I fix it?
### Q: My image logo behaves strangely. How can I fix it?
See troubleshooting section: <https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options#troubleshooting>
See the troubleshooting section: <https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options#troubleshooting>
### Q: Fastfetch runs in white and black on shell startup. Why?
### Q: Fastfetch runs in black and white on shell startup. Why?
This issue usually happens when using fastfetch with `p10k`. There are known incompatibility between fastfetch and p10k instant prompt.
The p10k doc clearly states that you should NOT print anything to stdout after `p10k-instant-prompt` is initialized. You should either put `fastfetch` before initialization of `p10k-instant-prompt` (recommended)
This issue usually occurs when using fastfetch with `p10k`. There are known incompatibilities between fastfetch and p10k instant prompt.
The p10k documentation clearly states that you should NOT print anything to stdout after `p10k-instant-prompt` is initialized. You should put `fastfetch` before the initialization of `p10k-instant-prompt` (recommended).
You can always use `fastfetch --pipe false` to force fastfetch running in colorful mode.
You can always use `fastfetch --pipe false` to force fastfetch to run in colorful mode.
### Q: Why do fastfetch and neofetch show different memory usage result?
### Q: Why do fastfetch and neofetch show different memory usage results?
See [#1096](https://github.com/fastfetch-cli/fastfetch/issues/1096).
### Q: Fastfetch shows less dpkg packages than neofetch, is it a bug?
### Q: Fastfetch shows fewer dpkg packages than neofetch. Is it a bug?
Neofetch incorrectly counts `rc` packages ( the package has been removed, but that the configuration files remain ). Bug https://github.com/dylanaraps/neofetch/issues/2278
Neofetch incorrectly counts `rc` packages (packages that have been removed but still have configuration files remaining). See bug: https://github.com/dylanaraps/neofetch/issues/2278
### Q: I use Debian / Ubuntu / Debian derived distro. My GPU is detected as `XXXX Device XXXX (VGA compatible)`. Is it a bug?
### Q: I use Debian / Ubuntu / Debian-derived distro. My GPU is detected as `XXXX Device XXXX (VGA compatible)`. Is this a bug?
Try upgrading `pci.ids`: Download <https://pci-ids.ucw.cz/v2.2/pci.ids> and overwrite file `/usr/share/hwdata/pci.ids`. For AMD GPUs, you should also upgrade `amdgpu.ids`: Download <https://gitlab.freedesktop.org/mesa/drm/-/raw/main/data/amdgpu.ids> and overwrite file `/usr/share/libdrm/amdgpu.ids`
Try upgrading `pci.ids`: Download <https://pci-ids.ucw.cz/v2.2/pci.ids> and overwrite the file `/usr/share/hwdata/pci.ids`. For AMD GPUs, you should also upgrade `amdgpu.ids`: Download <https://gitlab.freedesktop.org/mesa/drm/-/raw/main/data/amdgpu.ids> and overwrite the file `/usr/share/libdrm/amdgpu.ids`
Alternatively, you may try to use `fastfetch --gpu-driver-specific`, so that `fastfetch` will try to ask the driver for GPU name if supported.
Alternatively, you may try using `fastfetch --gpu-driver-specific`, which will make fastfetch attempt to ask the driver for the GPU name if supported.
### Q: I get error `Authorization required, but no authorization protocol specified` when running fastfetch in root
### Q: I get the error `Authorization required, but no authorization protocol specified` when running fastfetch as root
Try `export XAUTHORITY=$HOME/.Xauthority`
@@ -203,7 +214,7 @@ Try `fastfetch --wm-detect-plugin`. See also [#984](https://github.com/fastfetch
### Q: How can I change the colors of my ASCII logo?
Try `fastfetch --logo-color-[1-9] <color>`. `[1-9]` is the index of color placeholders.
Try `fastfetch --logo-color-[1-9] <color>`, where `[1-9]` is the index of color placeholders.
For example: `fastfetch --logo-color-1 red --logo-color-2 green`.
@@ -220,7 +231,7 @@ In JSONC, you can use:
}
```
### Q: How to hide a key?
### Q: How do I hide a key?
Set the key to a white space.
@@ -230,9 +241,59 @@ Set the key to a white space.
}
```
### Q: How can I display images on Windows?
As of April 2025:
#### mintty and Wezterm
mintty (used by Bash on Windows and MSYS2) and Wezterm (nightly build only) support the iTerm image protocol on Windows.
In `config.jsonc`:
```json
{
"logo": {
"type": "iterm",
"source": "C:/path/to/image.png",
"width": <num-in-chars>
}
}
```
#### Windows Terminal
Windows Terminal supports the sixel image protocol only.
* If you installed fastfetch through MSYS2:
1. Install imagemagick: `pacman -S mingw-w64-<subsystem>-x86_64-imagemagick`
2. In `config.jsonc`:
```jsonc
{
"logo": {
"type": "sixel", // DO NOT USE "auto"
"source": "C:/path/to/image.png", // Do NOT use `~` as fastfetch is a native Windows program and doesn't apply cygwin path conversion
"width": <image-width-in-chars>, // Optional
"height": <image-height-in-chars> // Optional
}
}
```
* If you installed fastfetch via scoop or downloaded the binary directly from the GitHub Releases page:
1. Convert your image manually to sixel format using [any online image conversion service](https://www.google.com/search?q=convert+image+to+sixel)
2. In `config.jsonc`:
```jsonc
{
"logo": {
"type": "raw", // DO NOT USE "auto"
"source": "C:/path/to/image.sixel",
"width": <image-width-in-chars>, // Required
"height": <image-height-in-chars> // Required
}
}
```
### Q: I want feature A / B / C. Will fastfetch support it?
Fastfetch is a system information tool. We only accept hardware or system level software feature requests. For most personal uses, I recommend using `Command` module to detect it yourself, which can be used to grab output from a custom shell script:
Fastfetch is a system information tool. We only accept hardware or system-level software feature requests. For most personal uses, I recommend using the `Command` module to implement custom functionality, which can be used to grab output from a custom shell script:
```jsonc
// This module shows the default editor
@@ -247,23 +308,28 @@ Fastfetch is a system information tool. We only accept hardware or system level
}
```
Otherwise, open a feature request in [GitHub Issues](https://github.com/fastfetch-cli/fastfetch/issues).
Otherwise, please open a feature request in [GitHub Issues](https://github.com/fastfetch-cli/fastfetch/issues).
### Q: I have questions. Where can I get help?
* For usage questions, please start a discussion in [GitHub Discussions](https://github.com/fastfetch-cli/fastfetch/discussions).
* For possible bugs, please open an issue in [GitHub Issues](https://github.com/fastfetch-cli/fastfetch/issues). Be sure to fill the bug-report template carefully for developers to investigate.
* For possible bugs, please open an issue in [GitHub Issues](https://github.com/fastfetch-cli/fastfetch/issues). Be sure to fill out the bug report template carefully to help developers investigate.
## Donate
If you find Fastfetch to be useful, please consider donating.
If you find Fastfetch useful, please consider donating.
* Current maintainer: [@CarterLi](https://paypal.me/zhangsongcui)
* Original author: [@LinusDierheimer](https://github.com/sponsors/LinusDierheimer)
## Code signing
* Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
* This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it
## Star History
Give it a star to support us!
Give us a star to show your support!
<a href="https://star-history.com/#fastfetch-cli/fastfetch&Date">
<picture>
+119 -428
View File
@@ -1,430 +1,121 @@
__fastfetch_complete_help()
{
local __ff_helps=(
"color"
"format"
"config"
"os-format"
"host-format"
"kernel-format"
"uptime-format"
"processes-format"
"packages-format"
"shell-format"
"display-format"
"de-format"
"wm-format"
"wmtheme-format"
"theme-format"
"icons-format"
"font-format"
"cursor-format"
"terminal-format"
"terminalfont-format"
"cpu-format"
"cpuusage-format"
"gpu-format"
"memory-format"
"swap-format"
"disk-format"
"battery-format"
"poweradapter-format"
"locale-format"
"localip-format"
"publicip-format"
"player-format"
"media-format"
"datetime-format"
"date-format"
"time-format"
"vulkan-format"
"opengl-format"
"opencl-format"
"bluetooth-format"
)
COMPREPLY=($(compgen -W "${__ff_helps[*]}" -- "$CURRENT_WORD"))
#!/usr/bin/env bash
_fastfetch() {
# Use Bash built-in variables directly
local cur="${COMP_WORDS[COMP_CWORD]}"
local prev="${COMP_WORDS[COMP_CWORD-1]}"
# Check if Python is available
if ! command -v python3 &>/dev/null; then
return
fi
# Handle standard completion cases
case "$prev" in
--color|--color-keys|--color-title|--color-output|--color-separator|--*-color|--*-key-color|--*-output-color|--logo-color-[1-9]|--percent-color-*|--temp-color-*)
local -a colors=("black" "red" "green" "yellow" "blue" "magenta" "cyan" "white" "default")
COMPREPLY=($(compgen -W "${colors[*]}" -- "$cur"))
return
;;
--logo|-l)
local -a logos
readarray -t logos < <(fastfetch --list-logos autocompletion 2>/dev/null)
logos+=("none" "small")
COMPREPLY=($(compgen -W "${logos[*]}" -- "$cur"))
return
;;
--config|-c)
local -a presets
readarray -t presets < <(fastfetch --list-presets autocompletion 2>/dev/null)
presets+=("none")
COMPREPLY=($(compgen -W "${presets[*]}" -- "$cur"))
# Also allow file path completion
if type _filedir &>/dev/null; then
_filedir
elif type compgen &>/dev/null; then
COMPREPLY+=($(compgen -f -- "$cur"))
fi
return
;;
--structure|-s)
# Get all module names in lowercase only
local -a structures
readarray -t structures < <(fastfetch --list-modules autocompletion 2>/dev/null | cut -d':' -f1 | tr '[:upper:]' '[:lower:]')
COMPREPLY=($(compgen -W "${structures[*]}" -- "$cur"))
return
;;
--help|-h)
local -a modules
readarray -t modules < <(fastfetch --list-modules autocompletion 2>/dev/null)
# Convert to lowercase and keep only module names
local -a module_names=()
for module in "${modules[@]}"; do
module_names+=($(echo "$module" | cut -d':' -f1 | tr '[:upper:]' '[:lower:]')-format)
done
module_names+=("format" "color")
COMPREPLY=($(compgen -W "${module_names[*]}" -- "$cur"))
return
;;
--format)
COMPREPLY=($(compgen -W "json default" -- "$cur"))
return
;;
--*-format)
# Format string completion, handle spaces
return
;;
--*path*|--*file*|--gen-config*|--*data*)
# File path completion
if type _filedir &>/dev/null; then
_filedir
elif type compgen &>/dev/null; then
COMPREPLY=($(compgen -f -- "$cur"))
fi
return
;;
esac
# If not a special option, generate all possible options
if [[ "$cur" == -* ]]; then
local -a opts
readarray -t opts < <(python3 - "$cur" <<'EOF'
import json
import sys
import subprocess
def main(current):
try:
# Use fastfetch --help-raw to get option data
output = subprocess.check_output(['fastfetch', '--help-raw'], stderr=subprocess.DEVNULL)
data = json.loads(output)
for category in data.values():
for flag in category:
if flag.get("pseudo", False):
continue
if "short" in flag:
print(f"-{flag['short']}")
if "long" in flag:
if flag["long"] == "logo-color-[1-9]":
for i in range(1, 10):
print(f"--logo-color-{i}")
else:
print(f"--{flag['long']}")
except Exception:
# If error occurs, return no options
pass
if __name__ == "__main__":
main(sys.argv[1])
EOF
)
COMPREPLY=($(compgen -W "${opts[*]}" -- "$cur"))
fi
return 0
}
__fastfetch_complete_bool()
{
COMPREPLY=($(compgen -W "true false" -- "$CURRENT_WORD"))
}
__fastfetch_complete_string()
{
if [[ $CURRENT_WORD != "" ]]; then
COMPREPLY=("$CURRENT_WORD")
fi
}
__fastfetch_complete_path()
{
COMPREPLY=($(compgen -A file -- "$CURRENT_WORD"))
}
__fastfetch_complete_logo()
{
COMPREPLY=($(compgen -W "$(fastfetch --list-logos autocompletion)" -- "$CURRENT_WORD"))
}
__fastfetch_complete_logo_type()
{
local __ff_logo_types=(
"auto"
"builtin"
"file"
"raw"
"sixel"
"kitty"
"chafa"
)
COMPREPLY=($(compgen -W "${__ff_logo_types[*]}" -- "$CURRENT_WORD"))
}
__fastfetch_complete_binary_prefix()
{
local __ff_size_binary_prefixes=(
"iec"
"si"
"jedec"
)
COMPREPLY=($(compgen -W "${__ff_size_binary_prefixes[*]}" -- "$CURRENT_WORD"))
}
__fastfetch_complete_gl()
{
local __ff_gl_types=(
"auto"
"egl"
"glx"
"osmesa"
)
COMPREPLY=($(compgen -W "${__ff_gl_types[*]}" -- "$CURRENT_WORD"))
}
__fastfetch_complete_option()
{
local FF_OPTIONS_ALL=(
"${FF_OPTIONS_BOOL[@]}"
"${FF_OPTIONS_STRING[@]}"
"${FF_OPTIONS_PATH[@]}"
"${FF_OPTIONS_LOGO[@]}"
"${FF_OPTIONS_LOGO_TYPE[@]}"
"${FF_OPTIONS_BINARY_PREFIX[@]}"
"${FF_OPTIONS_OPENGL[@]}"
)
if [[ $WORD_COUND -lt 3 ]]; then
FF_OPTIONS_ALL+=(
"${FF_OPTIONS_SINGLE[@]}"
"${FF_OPTIONS_HELP[@]}"
)
fi
for ff_word in ${COMP_WORDS[@]}; do
if [[ $ff_word == $CURRENT_WORD ]]; then
break
fi
FF_OPTIONS_ALL=("${FF_OPTIONS_ALL[@]/$ff_word}")
done
COMPREPLY=($(compgen -W "${FF_OPTIONS_ALL[*]}" -- "$CURRENT_WORD"))
}
__fastfetch_previous_matches()
{
for ff_option in "$@"; do
if [[ $ff_option == "$PREVIOUS_WORD" ]]; then
return 0
fi
done
return 1
}
__fastfetch_completion()
{
local CURRENT_WORD="${COMP_WORDS[$COMP_CWORD]}"
local PREVIOUS_WORD="${COMP_WORDS[$COMP_CWORD - 1]}"
local WORD_COUND="${#COMP_WORDS[@]}"
local FF_OPTIONS_SINGLE=(
"-v"
"--version"
"--list-logos"
"--list-modules"
"--list-presets"
"--list-features"
"--print-logos"
"--print-config-system"
"--print-config-user"
"--print-structure"
"--gen-config"
"--gen-config-force"
)
local FF_OPTIONS_HELP=(
"-h"
"--help"
)
local FF_OPTIONS_BOOL=(
"-r"
"--show-errors"
"--logo-print-remaining"
"--multithreading"
"--stat"
"--allow-slow-operations"
"--disable-linewrap"
"--hide-cursor"
"--cpu-temp"
"--gpu-temp"
"--battery-temp"
"--display-precise-refresh-rate"
"--localip-show-ipv4"
"--localip-show-ipv6"
"--localip-show-flags"
"--localip-show-loop"
"--localip-show-mtu"
"--localip-show-speed"
"--localip-name-prefix"
"--localip-compact-type"
"--escape-bedrock"
"--pipe"
"--title-fqdn"
"--disk-folders"
"--disk-show-external"
"--disk-show-hidden"
"--disk-show-subvolumes"
"--gpu-hide-integrated"
"--gpu-hide-discrete"
"--gpu-force-method"
"--disk-show-unknown"
"--bluetooth-show-disconnected"
)
local FF_OPTIONS_STRING=(
"--logo-type"
"--logo-padding"
"--logo-padding-left"
"--logo-padding-right"
"--logo-padding-top"
"--logo-color-1"
"--logo-color-2"
"--logo-color-3"
"--logo-color-4"
"--logo-color-5"
"--logo-color-6"
"--logo-color-7"
"--logo-color-8"
"--logo-color-9"
"--logo-width"
"--logo-height"
"--color"
"--color-keys"
"--color-title"
"--display-compact-type"
"--separator"
"-s"
"--structure"
"--player-name"
"--percent-type"
"--publicip-url"
"--publicip-timeout"
"--weather-output-format"
"--weather-timeout"
"--os-key"
"--os-format"
"--os-key-color"
"--host-key"
"--host-format"
"--host-key-color"
"--kernel-key"
"--kernel-format"
"--kernel-key-color"
"--uptime-key"
"--uptime-format"
"--uptime-key-color"
"--processes-key"
"--processes-format"
"--processes-key-color"
"--packages-key"
"--packages-format"
"--packages-key-color"
"--shell-key"
"--shell-format"
"--shell-key-color"
"--display-key"
"--display-format"
"--display-key-color"
"--de-key"
"--de-format"
"--de-key-color"
"--wm-key"
"--wm-format"
"--wm-key-color"
"--wmtheme-key"
"--wmtheme-format"
"--wmtheme-key-color"
"--theme-key"
"--theme-format"
"--theme-key-color"
"--icons-key"
"--icons-format"
"--icons-key-color"
"--font-key"
"--font-format"
"--font-key-color"
"--cursor-key"
"--cursor-format"
"--cursor-key-color"
"--terminal-key"
"--terminal-format"
"--terminal-key-color"
"--terminalfont-key"
"--terminalfont-format"
"--terminalfont-key-color"
"--cpu-key"
"--cpu-format"
"--cpu-key-color"
"--cpu-useage-key"
"--cpu-useage-format"
"--cpu-useage-key-color"
"--gpu-key"
"--gpu-format"
"--gpu-key-color"
"--memory-key"
"--memory-format"
"--memory-key-color"
"--swap-key"
"--swap-format"
"--swap-key-color"
"--disk-key"
"--disk-format"
"--disk-key-color"
"--battery-key"
"--battery-format"
"--battery-key-color"
"--poweradapter-key"
"--poweradapter-format"
"--poweradapter-key-color"
"--locale-key"
"--locale-format"
"--locale-key-color"
"--localip-key"
"--localip-format"
"--localip-key-color"
"--publicip-key"
"--publicip-format"
"--publicip-key-color"
"--wifi-key"
"--wifi-format"
"--wifi-key-color"
"--weather-key"
"--weather-format"
"--weather-key-color"
"--player-key"
"--player-format"
"--player-key-color"
"--media-key"
"--media-format"
"--media-key-color"
"--datetime-key"
"--datetime-format"
"--datetime-key-color"
"--date-key"
"--date-format"
"--date-key-color"
"--time-key"
"--time-format"
"--time-key-color"
"--vulkan-key"
"--vulkan-format"
"--vulkan-key-color"
"--opengl-key"
"--opengl-format"
"--opengl-key-color"
"--opencl-key"
"--opencl-format"
"--opencl-key-color"
"--users-key"
"--users-format"
"--users-key-color"
"--users-myself-only"
"--bluetooth-key"
"--bluetooth-format"
"--bluetooth-key-color"
)
local FF_OPTIONS_PATH=(
"-c"
"--config"
"--lib-vulkan"
"--lib-wayland"
"--lib-xcb-randr"
"--lib-xcb"
"--lib-xrandr"
"--lib-X11"
"--lib-gio"
"--lib-dconf"
"--lib-dbus"
"--lib-xfconf"
"--lib-sqlite3"
"--lib-rpm"
"--lib-imagemagick"
"--lib-z"
"--lib-chafa"
"--lib-egl"
"--lib-glx"
"--lib-osmesa"
"--lib-opencl"
"--lib-pulse"
"--lib-ddcutil"
"--lib-nm"
)
local FF_OPTIONS_LOGO=(
"-l"
"--logo"
)
local FF_OPTIONS_LOGO_TYPE=(
"--logo-type"
)
local FF_OPTIONS_BINARY_PREFIX=(
"--binary-prefix"
)
local FF_OPTIONS_OPENGL=(
"--opengl-type"
)
if __fastfetch_previous_matches "${FF_OPTIONS_SINGLE[@]}"; then
return
elif [[ $WORD_COUND -gt 3 && ( ${COMP_WORDS[$COMP_CWORD - 2]} == "--help" || ${COMP_WORDS[$COMP_CWORD - 2]} == "-h" ) ]]; then
return
elif [[ $CURRENT_WORD == "-"* ]]; then
__fastfetch_complete_option
elif __fastfetch_previous_matches "${FF_OPTIONS_HELP[@]}"; then
__fastfetch_complete_help
elif __fastfetch_previous_matches "${FF_OPTIONS_BOOL[@]}"; then
__fastfetch_complete_bool
elif __fastfetch_previous_matches "${FF_OPTIONS_STRING[@]}"; then
__fastfetch_complete_string
elif __fastfetch_previous_matches "${FF_OPTIONS_PATH[@]}"; then
__fastfetch_complete_path
elif __fastfetch_previous_matches "${FF_OPTIONS_LOGO[@]}"; then
__fastfetch_complete_logo
elif __fastfetch_previous_matches "${FF_OPTIONS_LOGO_TYPE[@]}"; then
__fastfetch_complete_logo_type
elif __fastfetch_previous_matches "${FF_OPTIONS_BINARY_PREFIX[@]}"; then
__fastfetch_complete_binary_prefix
elif __fastfetch_previous_matches "${FF_OPTIONS_OPENGL[@]}"; then
__fastfetch_complete_gl
else
__fastfetch_complete_option
fi
}
complete -F __fastfetch_completion fastfetch
# Register completion
complete -F _fastfetch fastfetch
+8 -1
View File
@@ -62,11 +62,17 @@ end
echo '
import json, subprocess, sys
def main():
data: dict[str, list[dict]] = json.loads(subprocess.check_output(["fastfetch", "--help-raw"]))
for key in data:
for flag in data[key]:
if flag["long"] == "logo-color-[1-9]":
for i in range(1, 10):
print(f"""complete -c fastfetch -d "{flag["desc"]}" -l "logo-color-{i}" -x -a "(__fastfetch_complete_color)" """)
continue
if flag.get("pseudo", False):
continue
@@ -75,7 +81,7 @@ def main():
command_prefix += f""" -o {flag["short"]}"""
if "arg" in flag:
type: str = flag["arg"]["type"];
type: str = flag["arg"]["type"]
if type == "bool":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
elif type == "color":
@@ -98,6 +104,7 @@ def main():
else:
print(f"{command_prefix} -f")
if __name__ == "__main__":
try:
main()
+133 -1
View File
@@ -1,3 +1,136 @@
fastfetch (2.54.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Fix building on plucky
-- Carter Li <zhangsongcui@live.cn> Mon, 20 Oct 2025 14:27:02 +0800
fastfetch (2.54.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.54.0
* Test independent changelog entries for different Ubuntu releases
-- Carter Li <zhangsongcui@live.cn> Mon, 20 Oct 2025 10:47:02 +0800
fastfetch (2.53.0) jammy; urgency=medium
* Update to 2.53.0
-- Carter Li <zhangsongcui@live.cn> Tue, 23 Sep 2025 09:58:48 +0800
fastfetch (2.52.0) jammy; urgency=medium
* Update to 2.52.0
-- Carter Li <zhangsongcui@live.cn> Fri, 05 Sep 2025 14:59:44 +0800
fastfetch (2.51.0) jammy; urgency=medium
* Update to 2.51.0
-- Carter Li <zhangsongcui@live.cn> Fri, 29 Aug 2025 08:55:03 +0800
fastfetch (2.50.2) jammy; urgency=medium
* Update to 2.50.2
-- Carter Li <zhangsongcui@live.cn> Thu, 21 Aug 2025 10:33:07 +0800
fastfetch (2.49.0) jammy; urgency=medium
* Update to 2.49.0
-- Carter Li <zhangsongcui@live.cn> Thu, 31 Jul 2025 14:32:59 +0800
fastfetch (2.48.0) jammy; urgency=medium
* Update to 2.48.0
-- Carter Li <zhangsongcui@live.cn> Thu, 17 Jul 2025 16:16:52 +0800
fastfetch (2.47.0) jammy; urgency=medium
* Update to 2.47.0
-- Carter Li <zhangsongcui@live.cn> Thu, 03 Jul 2025 14:51:45 +0800
fastfetch (2.46.0) jammy; urgency=medium
* Update to 2.46.0
-- Carter Li <zhangsongcui@live.cn> Fri, 20 Jun 2025 15:01:21 +0800
fastfetch (2.45.0) jammy; urgency=medium
* Update to 2.45.0
-- Carter Li <zhangsongcui@live.cn> Thu, 05 Jun 2025 10:56:38 +0800
fastfetch (2.44.0) jammy; urgency=medium
* Update to 2.44.0
-- Carter Li <zhangsongcui@live.cn> Mon, 26 May 2025 14:59:01 +0800
fastfetch (2.43.0) jammy; urgency=medium
* Update to 2.43.0
-- Carter Li <zhangsongcui@live.cn> Wed, 14 May 2025 09:49:50 +0800
fastfetch (2.42.0) jammy; urgency=medium
* Update to 2.42.0
-- Carter Li <zhangsongcui@live.cn> Wed, 30 Apr 2025 14:08:57 +0800
fastfetch (2.41.0) jammy; urgency=medium
* Update to 2.41.0
-- Carter Li <zhangsongcui@live.cn> Wed, 16 Apr 2025 13:42:58 +0800
fastfetch (2.40.4) jammy; urgency=medium
* Update to 2.40.4
-- Carter Li <zhangsongcui@live.cn> Thu, 10 Apr 2025 15:38:21 +0800
fastfetch (2.40.3) jammy; urgency=medium
* Update to 2.40.3
-- Carter Li <zhangsongcui@live.cn> Mon, 07 Apr 2025 09:29:27 +0800
fastfetch (2.40.0) jammy; urgency=medium
* Update to 2.40.0
-- Carter Li <zhangsongcui@live.cn> Thu, 03 Apr 2025 08:46:54 +0800
fastfetch (2.39.1) jammy; urgency=medium
* Update to 2.39.1
-- Carter Li <zhangsongcui@live.cn> Fri, 21 Mar 2025 11:02:19 +0800
fastfetch (2.39.0ubuntu1) jammy; urgency=medium
* Remove unwanted debugging code
-- Carter Li <zhangsongcui@live.cn> Thu, 20 Mar 2025 10:39:22 +0800
fastfetch (2.39.0) jammy; urgency=medium
* Update to 2.39.0
-- Carter Li <zhangsongcui@live.cn> Thu, 20 Mar 2025 10:35:18 +0800
fastfetch (2.38.0) jammy; urgency=medium
* Update to 2.38.0
-- Carter Li <zhangsongcui@live.cn> Wed, 05 Mar 2025 14:56:24 +0800
fastfetch (2.37.0) jammy; urgency=medium
* Update to 2.37.0
@@ -315,4 +448,3 @@ fastfetch (2.7.1) jammy; urgency=medium
* Initial release.
-- Carter Li <zhangsongcui@live.cn> Tue, 06 Feb 2024 15:01:11 +0800
+1 -1
View File
@@ -2,7 +2,7 @@ Source: fastfetch
Section: universe/utils
Priority: optional
Maintainer: Carter Li <zhangsongcui@live.cn>
Build-Depends: libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libxfconf-0-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, libosmesa6-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
Standards-Version: 4.0.0
Homepage: https://github.com/fastfetch-cli/fastfetch
-1
View File
@@ -1 +0,0 @@
fastfetch_2.37.0_source.buildinfo universe/utils optional
+74 -2
View File
@@ -1,4 +1,76 @@
#!/usr/bin/env bash
# WARNING: DO NOT RUN THIS SCRIPT UNLESS YOU KNOW WHAT YOU ARE DOING.
debuild -S -i -I
dput ppa:zhangsongcui3371/fastfetch ~/fastfetch_*.changes
set -euo pipefail
command -v debuild >/dev/null 2>&1 || { echo "debuild not found. Install devscripts." >&2; exit 1; }
command -v dput >/dev/null 2>&1 || { echo "dput not found." >&2; exit 1; }
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
OUT_DIR="$(dirname "$ROOT_DIR")"
PPA="ppa:zhangsongcui3371/fastfetch"
CODENAMES=( jammy noble plucky questing resolute )
DRY_RUN=0
if [[ -d "$OUT_DIR/build" ]]; then
echo "Output directory exists: $OUT_DIR/build" >&2
echo "Please move or delete it before proceeding." >&2
exit 1
fi
TEMPLATE="$ROOT_DIR/debian/changelog.tpl"
CHANGELOG_DEBIAN="$ROOT_DIR/debian/changelog"
if [[ ! -f "$TEMPLATE" ]]; then
echo "Template not found: $TEMPLATE" >&2
exit 1
fi
if ! grep -q '#UBUNTU_CODENAME#' "$TEMPLATE"; then
echo "Template missing placeholder: #UBUNTU_CODENAME#" >&2
exit 1
fi
echo "IMPORTANT: Before proceeding, please ensure that 'debian/changelog.tpl' is up-to-date"
echo " with the correct version number, release notes, and maintainer information."
echo
echo " The template must contain a placeholder like '#UBUNTU_CODENAME#' for the codename."
echo
read -p "Have you reviewed and updated 'debian/changelog.tpl'? (y/N): " -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
cleanup() {
rm -f "$CHANGELOG_DEBIAN"
rm -f "$ROOT_DIR/debian/files"
}
trap cleanup EXIT
shopt -s nullglob
for codename in "${CODENAMES[@]}"; do
echo "==> Publishing distro: $codename"
sed "s/#UBUNTU_CODENAME#/${codename}/g" "$TEMPLATE" > "$CHANGELOG_DEBIAN"
( cd "$ROOT_DIR" && debuild -S -i -I )
changes=( "$OUT_DIR"/fastfetch_*~${codename}_source.changes )
if [[ ${#changes[@]} -ne 1 ]]; then
echo "Unable to uniquely identify .changes for '$codename' in: $OUT_DIR" >&2
printf 'Found:\n'; printf ' %s\n' "${changes[@]}" >&2 || true
exit 1
fi
if [[ $DRY_RUN -eq 1 ]]; then
echo "[DRY-RUN] dput \"$PPA\" \"${changes[0]}\""
else
dput "$PPA" "${changes[0]}"
fi
rm -f "$OUT_DIR"/fastfetch_*~${codename}_source.{changes,dsc,tar.*}
echo "<== Done: $codename"
done
+140 -59
View File
@@ -1,8 +1,7 @@
.TH FASTFETCH 1 "@FASTFETCH_BUILD_DATE@" "@CMAKE_PROJECT_NAME@ @CMAKE_PROJECT_VERSION@"
.SH NAME
fastfetch \- a neofetch\-like tool for fetching system information and
displaying them in a pretty way
fastfetch \- a fast and customizable system information tool similar to neofetch
.SH SYNOPSIS
@@ -11,15 +10,12 @@ displaying them in a pretty way
.SH DESCRIPTION
Fastfetch is a neofetch\-like tool for fetching system information and
displaying them in a pretty way. It is written mainly in C, with performance
and customizability in mind.
Currently, Linux, Android, FreeBSD, MacOS and Windows 7+ are supported.
Fastfetch is a tool for displaying system information in a visually appealing way. Written primarily in C, it focuses on performance and customizability while providing functionality similar to neofetch.
It supports Linux, Android, *BSD, macOS, Haiku, and Windows 7 or newer.
.SH "EXIT STATUS"
On successful execution, fastfetch returns zero. If any error happened,
the exit code will be non\-zero.
Fastfetch returns zero on successful execution. Any errors result in a non-zero exit code.
.SH OPTIONS
@@ -27,115 +23,200 @@ the exit code will be non\-zero.
.TP
.B \-h, \-\-help \fI[command]
Show help output, displaying all available options or help for given command
Display help information for all available options or for a specific command
.TP
.B \-v, \-\-version
Show version of fastfetch
Display the version of fastfetch
.TP
.B \-\-version\-raw
Display the raw version string (major.minor.patch)
.TP
.B \-\-list\-config\-paths
List search paths of config files
List search paths for configuration files
.TP
.B \-\-list\-data\-paths
List search paths of presets and logos
List search paths for presets and logos
.TP
.B \-\-list\-logos
List available logos, they can be loaded with \fI\-\-logo
List available logos that can be loaded with \fI\-\-logo
.TP
.B \-\-list\-modules
List available modules
List all available modules
.TP
.B \-\-list\-presets
List available presets, they can be loaded with \fI\-\-config
List available presets that can be loaded with \fI\-\-config
.TP
.B \-\-list\-features
List the supported features fastfetch was compiled with
List the features that fastfetch was compiled with (mainly for development)
.TP
.B \-\-print\-logos
Print available logos
Display all available logos
.TP
.B \-\-print\-structure
Print the default structure
Display the default structure
.TP
.B \-\-format \fI<type>
Set the output format. Besides the
.I default
format, only
.I json
is supported currently.
.SS "Display Options"
.TP
.B \-l, \-\-logo \fI<logo>
Set the logo to display
.TP
.B \-s, \-\-structure \fI<structure>
Set the structure of the fetch. For details about the structure,
see the CONFIGURATION section.
Set the output format. Available options are:
.RS
.IP \(bu 2
\fIdefault\fR: Default human-readable format
.IP \(bu 2
\fIjson\fR: JSON format for machine processing
.RE
.SS "Config Options"
.TP
.B \-c, \-\-config \fI<config>
Use the specified config file or preset. If
.I none
is specified, disable further config loading. For details about
config files, see the CONFIGURATION section
Use the specified config file or preset. Specify \fInone\fR to disable further config loading. See the CONFIGURATION section for details on config files.
.TP
.B \-\-gen\-config \fI[file]
Generate a config file with options specified on the command line.
If \fIfile\fR is specified, the configuration will be written to the
file, otherwise it will be written to stdout.
.B \-\-gen\-config \fI[path]
Generate a config file with options specified on the command line. If \fIpath\fR is not specified, it defaults to \fB~/.config/fastfetch/config.jsonc\fR. If \fIpath\fR is "\-", the configuration will be written to stdout.
.TP
.B \-\-gen\-config\-force \fI[file]
Same as \fB\-\-gen\-config\fR, but overwrites existing config
.B \-\-gen\-config\-force \fI[path]
Same as \fB\-\-gen\-config\fR, but overwrites any existing file at the destination path.
.TP
.SS "Logo Options"
.TP
To list all options, use \fB\-\-help\fR. It will also print all available module options.
.B \-l, \-\-logo \fI<logo>
Set the logo to display. Can be the name of a built-in logo or a path to an image file. Use \fInone\fR to disable the logo.
.TP
.B \-\-logo\-type \fI<type>
Set the type of the logo specified with \fI\-\-logo\fR. Available types include \fIauto\fR, \fIbuiltin\fR, \fIfile\fR, \fIsixel\fR, \fIkitty\fR, and others. See \fB\-\-help logo\-type\fR for details.
.TP
.B \-\-logo\-width \fI<width>
Set the width of the logo in characters (for image logos)
.TP
.B \-\-logo\-height \fI<height>
Set the height of the logo in characters (for image logos)
.TP
.B \-\-logo\-color\-[1\-9] \fI<color>
Override specific colors in the logo
.SS "Display Options"
.TP
.B \-s, \-\-structure \fI<structure>
Set the structure of the fetch (a colon-separated list of module names)
.TP
.B \-\-color \fI<color>
Set the color of keys and title. See \fB\-\-help color\fR for available colors.
.TP
.B \-\-color\-keys \fI<color>
Set the color of keys only
.TP
.B \-\-color\-title \fI<color>
Set the color of the title only
.TP
.B \-\-separator \fI<string>
Set the separator between key and value (default: ": ")
.TP
.B \-\-key\-width \fI<num>
Align the width of keys to \fI<num>\fR characters
.TP
.B \-\-show\-errors
Display errors when they occur (default: false)
.TP
.B \-\-pipe
Disable colors (automatically detected based on whether stdout is a terminal)
To list all available options including module-specific options, use \fB\-\-help\fR.
.SH CONFIGURATION
.SS "Fetch Structure"
The structure of a fetch describes the modules that should be included in
the output. It consists of a string of modules, separated by a colon (:).
The structure defines which modules to display and in what order. It consists of module names separated by colons (:).
For example: \fBtitle:separator:os:kernel:uptime\fR
To list all available modules, use \fB\-\-list\-modules\fR
.SS "Config Files"
Fastfetch uses JSONC based format for configuration. Fastfetch doesn't generate
config file automatically; it should be generated manually by \fB\-\-gen\-config\fR.
The config file will be saved in \fB~/.config/fastfetch/config.jsonc\fR by default.
Fastfetch uses JSONC for configuration files. JSONC is JSON with support for comments (// and /* */). Configuration files must have the .jsonc extension.
A JSONC config file is a JSON file that also supports comments with (// and /* */).
Those files must have the extension '.jsonc'.
You can generate a default config file using \fB\-\-gen\-config\fR. By default, the config file is saved at \fB~/.config/fastfetch/config.jsonc\fR.
The specified configuration/preset files are searched in the following order:
The configuration/preset files are searched in the following locations (in order):
1. relative to the current working directory
.RS
.IP 1. 4
Relative to the current working directory
.IP 2. 4
Relative to ~/.local/share/fastfetch/presets/
.IP 3. 4
Relative to /usr/share/fastfetch/presets/
.RE
2. relative to ~/.local/share/fastfetch/presets/
For detailed information on logo options, module configuration, and formatting, visit:
.RS
\fIhttps://github.com/fastfetch-cli/fastfetch/wiki/Configuration\fR
.RE
3. relative to /usr/share/fastfetch/presets/
Fastfetch provides several built-in presets. List them with \fB\-\-list\-presets\fR.
Fastfetch provides some default presets. List them with \fB\-\-list\-presets\fR.
.SS "JSON Schema"
A JSON schema is available for editor intelligence when editing the configuration file. Add the following line at the beginning of your config file:
.PP
\fB"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json"\fR
.SH EXAMPLES
.TP
Basic usage:
.RS
\fBfastfetch\fR
.RE
.TP
Use a specific logo:
.RS
\fBfastfetch \-\-logo arch\fR
.RE
.TP
Custom structure:
.RS
\fBfastfetch \-\-structure title:os:kernel:uptime:memory\fR
.RE
.TP
Generate a config file:
.RS
\fBfastfetch \-\-gen\-config\fR
.RE
.TP
Use a preset:
.RS
\fBfastfetch \-\-config neofetch\fR
.RE
.SH "SEE ALSO"
.BR neofetch (1)
.SH BUGS
Please report bugs to: \fIhttps://github.com/fastfetch\-cli/fastfetch/issues\fR
.SH AUTHORS
Fastfetch is developed by a team of contributors on GitHub.
Visit \fIhttps://github.com/fastfetch-cli/fastfetch\fR for more information.
+1285 -299
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -52,7 +52,10 @@
},
"memory",
"physicalmemory",
"swap",
{
"type": "swap",
"separate": true
},
"disk",
"btrfs",
"zpool",
+4 -1
View File
@@ -54,7 +54,10 @@
},
"memory",
"physicalmemory",
"swap",
{
"type": "swap",
"separate": true
},
"disk",
"btrfs",
"zpool",
+5 -4
View File
@@ -12,10 +12,11 @@
"type": ["bar", "hide-others"]
},
"bar": {
"borderLeft": "",
"borderRight": "",
"charElapsed": "█",
"charTotal": "░",
"border": null,
"char": {
"elapsed": "█",
"total": "░"
},
"width": 40
},
"constants": [
+11 -11
View File
@@ -28,38 +28,38 @@
{
"type": "title",
"key": "{#90}{$1}│ {#92}User {#90}│",
"format": "{$2}{$3}{user-name} {#2}[{home-dir}]"
"format": "{$2}{$3}{user-name} {#2}[{home-dir}]"
},
{
"type": "users",
"key": "{#90}{$1}│ {#92}Users {#90}│",
"myselfOnly": false,
"format": "{$2}{$3}{1}@{host-name}{/host-name}localhost{/}{?client-ip} {#2}[IP:{client-ip}]{?} {#2}[Login time: {login-time}]",
"format": "{$2}{$3}{1}@{host-name}{/host-name}localhost{/}{?client-ip} {#2}[IP:{client-ip}]{?} [Login time: {login-time}]"
},
{
"type": "datetime",
"key": "{#90}{$1}│ {#92}Datetime {#90}│",
"format": "{$2}{$3}{year}-{month-pretty}-{day-in-month} {hour-pretty}:{minute-pretty}:{second-pretty} {#2}{weekday} {#2}[W{week}] {#2}[UTC{offset-from-utc}]"
"format": "{$2}{$3}{year}-{month-pretty}-{day-in-month} {hour-pretty}:{minute-pretty}:{second-pretty} [{weekday}] [W{week}] [UTC{offset-from-utc}]"
},
{
"type": "title",
"key": "{#90}{$1}│ {#93}Host: {#90}│",
"format": "{$2}{$3}{#1}{#36}{host-name}"
"key": "{#90}{$1}│ {#93}Host {#90}│",
"format": "{$2}{$3}{host-name}"
},
{
"type": "host",
"key": "{#90}{$1}│ {#93}Machine {#90}│",
"format": "{$2}{$3}{name} {#2}{version}"
"format": "{$2}{$3}{name} {#2}{version}"
},
{
"type": "os",
"key": "{#90}{$1}│ {#93}OS {#90}│",
"format": "{$2}{$3}{pretty-name} {codename} {#2}[v{version}] {#2}[{arch}]"
"format": "{$2}{$3}{?pretty-name}{pretty-name}{?}{/pretty-name}{name}{/} {codename} {#2}[v{version}] [{arch}]"
},
{
"type": "kernel",
"key": "{#90}{$1}│ {#93}Kernel {#90}│",
"format": "{$2}{$3}{sysname} {#2}[v{release}]"
"format": "{$2}{$3}{sysname} {#2}[v{release}]"
},
{
"type": "uptime",
@@ -71,14 +71,14 @@
"key": "{#90}{$1}│ {#91}CPU {#90}│",
"showPeCoreCount": true,
"temp": true,
"format": "{$2}{$3}{name} {#2}[C:{core-types}] {#2}[{freq-max}]"
"format": "{$2}{$3}{name} {#2}[C:{core-types}] [{freq-max}]"
},
{
"type": "gpu",
"key": "{#90}{$1}│ {#91}GPU {#90}│",
"detectionMethod": "auto",
"driverSpecific": true,
"format": "{$2}{$3}{name} {#2}[C:{core-count}] {#2}[{type}]"
"format": "{$2}{$3}{name} {#2}[C:{core-count}]{?frequency} [{frequency}]{?} [{type}]"
},
{
"type": "memory",
@@ -98,7 +98,7 @@
{
"type": "terminal",
"key": "{#90}{$1}│ {#95}Terminal {#90}│",
"format": "{$2}{$3}{pretty-name} {#2}[{version}] [PID:{pid}]"
"format": "{$2}{$3}{pretty-name} {#2}[{version}] [PID:{pid}]"
},
{
"type": "terminalfont",
+95 -21
View File
@@ -6,11 +6,13 @@
"keys": "blue"
},
"separator": "",
// Constants are reusable strings referenced by {$1}, {$2}, etc.
// These contain ANSI escape codes for cursor positioning
"constants": [
"──────────────────────────────────────────────",
"\u001b[47D",
"\u001b[47C",
"\u001b[46C"
"──────────────────────────────────────────────", // {$1} - horizontal line for borders
"\u001b[47D", // {$2} - move cursor left 47 columns
"\u001b[47C", // {$3} - move cursor right 47 columns
"\u001b[46C" // {$4} - move cursor right 46 columns
],
"brightColor": false
},
@@ -22,6 +24,24 @@
},
{
"type": "os",
// Key format breakdown for OS module:
// "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
//
// │ - Left border of key block
// {icon} - OS icon (defined internally by fastfetch)
// \u001b[s - ANSI escape: save cursor position (ESC[s)
// {sysname} - Format variable: system name (e.g., "Linux", "Darwin")
// \u001b[u - ANSI escape: restore cursor to saved position (ESC[u)
// Necessary because the length of `{sysname}` differs between different platforms
// \u001b[10C - ANSI escape: move cursor right 10 columns (ESC[10C)
// │ - Right border of key block (always 10 columns from left border)
// {$3} - Reference to constants[2]: move cursor right 47 columns
// │ - Right border of value block
// {$2} - Reference to constants[1]: move cursor left 47 columns
//
// This creates a fixed-width layout where the key block is exactly 10 columns wide,
// regardless of the actual content length. The cursor manipulation ensures proper
// alignment for the table-like structure.
"key": "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
},
{
@@ -34,7 +54,7 @@
"key": "│ {icon} Locale │{$3}│{$2}"
},
// Hardware
// Hardware section with cyan color theme
{
"type": "custom",
"key": "│{#cyan}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
@@ -42,6 +62,11 @@
},
{
"type": "chassis",
// Similar structure but with cyan color formatting:
// │{#cyan}│ - Left border with cyan color
// {icon} - Chassis icon
// Chassis - Fixed label text
// │{$4}│{#keys}│{$2} - Positioning and borders for value area
"key": "│{#cyan}│ {icon} Chassis │{$4}│{#keys}│{$2}"
},
{
@@ -76,7 +101,7 @@
"format": ""
},
// Desktop
// Desktop section with green color theme
{
"type": "custom",
"key": "│{#green}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
@@ -106,7 +131,7 @@
"format": ""
},
// Terminal
// Terminal section with yellow color theme
{
"type": "custom",
"key": "│{#yellow}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
@@ -138,7 +163,7 @@
"format": ""
},
// Development
// Development section with red color theme
{
"type": "custom",
"key": "│{#red}┌──────────────┬{$1}┐{#keys}│\u001b[39D",
@@ -146,31 +171,44 @@
},
{
"type": "command",
"keyIcon": "",
"keyIcon": "", // Custom icon override
"key": "│{#red}│ {icon} Rust │{$4}│{#keys}│{$2}",
"text": "rustc --version | cut -d' ' -f2",
"format": "rustc {}"
"text": "rustc --version",
"format": "rustc {~6,13}" // Print 6th to 13th characters (version number)
},
{
"type": "command",
"condition": {
"!system": "Windows" // Posix version
},
"keyIcon": "",
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
"text": "clang --version | head -1 | awk '{print $NF}'",
"text": "clang --version | sed -n 's/.*version \\([0-9][0-9.]*\\).*/\\1/p'",
"format": "clang {}"
},
{
"type": "command",
"condition": {
"system": "Windows" // Windows version
},
"keyIcon": "",
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
"text": "clang --version | findstr version", // Finds the line with "version"
"format": "clang {~-6}" // Prints the last 6 characters (version number)
},
{
"type": "command",
"keyIcon": "",
"key": "│{#red}│ {icon} NodeJS │{$4}│{#keys}│{$2}",
"text": "node --version",
"format": "node {~1}"
"format": "node {~1}" // {~1} removes first character (v)
},
{
"type": "command",
"keyIcon": "",
"key": "│{#red}│ {icon} Go │{$4}│{#keys}│{$2}",
"text": "go version | cut -d' ' -f3",
"format": "go {~2}"
"format": "go {~2}" // {~2} removes first 2 characters (go)
},
{
"type": "command",
@@ -200,7 +238,7 @@
"format": ""
},
// Uptime
// Uptime section with magenta color theme
{
"type": "custom",
"key": "│{#magenta}┌──────────────┬{$1}┐{#keys}│\u001b[36D",
@@ -212,15 +250,28 @@
},
{
"type": "users",
"myselfOnly": true,
"myselfOnly": true, // Only show current user
"keyIcon": "",
"key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}"
},
{
"condition": { // Conditional module: only show on non-macOS
"!system": "macOS"
},
"type": "disk",
"keyIcon": "",
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
"folders": "/", // On macOS, "/System/Volumes/VM" works for me
"folders": "/", // Check root filesystem
"format": "{create-time:10} [{days} days]" // Show creation time and age in days
},
{
"condition": { // Conditional module: only show on macOS
"system": "macOS"
},
"type": "disk",
"keyIcon": "",
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
"folders": "/System/Volumes/VM", // Work around for APFS on macOS
"format": "{create-time:10} [{days} days]"
},
{
@@ -230,12 +281,35 @@
},
{
"type": "custom",
"key": "└─────────────────{$1}┘",
"key": "└─────────────────{$1}┘", // Bottom border of the entire layout
"format": ""
},
// End
"break",
"colors"
// End with color palette and line break
"break", // Add a blank line
"colors" // Display color palette
]
}
/*
Key Format Structure Explanation:
The key format uses a combination of:
1. Unicode box drawing characters ( ) for borders
2. ANSI escape codes for cursor positioning (\u001b[...)
3. Format variables ({icon}, {sysname}, etc.)
4. Constant references ({$1}, {$2}, etc.)
5. Color formatting ({#color})
ANSI Escape Codes Used:
- \u001b[s - Save cursor position (ESC[s)
- \u001b[u - Restore cursor position (ESC[u)
- \u001b[nC - Move cursor right n columns (ESC[nC)
- \u001b[nD - Move cursor left n columns (ESC[nD)
This creates a table-like layout with fixed column widths and proper alignment,
regardless of the actual content length in each field.
For more ANSI escape code reference, see:
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#cursor-controls
*/
+165
View File
@@ -0,0 +1,165 @@
// Modified from: 24.jsonc
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"padding": {
"top": 2
}
},
"display": {
"separator": "",
"constants": [
// CONSTANT {$1} - VERTICAL BARS AT START AND 75th CHARACTERS FORWARD AND BACKWARD
"\u001b[90m│ │\u001b[60D\u001b[39m"
]
},
"modules": [
// CUSTOM - Top UI bar
{
"type": "custom",
"key": "{#90}╭ Keys ───────╮",
"format": "{#90}╭ Values ────────────────────────────────────────────────────╮",
},
{
"type": "title",
"key": "{#90}│ {#92}User {#90}│",
"format": "{$1}{user-name} {#2}[{home-dir}]"
},
{
"type": "users",
"key": "{#90}│ {#92}Users {#90}│",
"myselfOnly": false,
"format": "{$1}{1}@{host-name}{/host-name}localhost{/}{?client-ip} {#2}[IP:{client-ip}]{?} [Login time: {login-time}]"
},
{
"type": "datetime",
"key": "{#90}│ {#92}Datetime {#90}│",
"format": "{$1}{year}-{month-pretty}-{day-in-month} {hour-pretty}:{minute-pretty}:{second-pretty} {#2}[{weekday}] [W{week}] [UTC{offset-from-utc}]"
},
{
"type": "title",
"key": "{#90}│ {#93}Host {#90}│",
"format": "{$1}{host-name}"
},
{
"type": "host",
"key": "{#90}│ {#93}Machine {#90}│",
"format": "{$1}{name} {#2}{version}"
},
{
"type": "os",
"key": "{#90}│ {#93}OS {#90}│",
"format": "{$1}{?pretty-name}{pretty-name}{?}{/pretty-name}{name}{/} {codename} {#2}[v{version}] [{arch}]"
},
{
"type": "kernel",
"key": "{#90}│ {#93}Kernel {#90}│",
"format": "{$1}{sysname} {#2}[v{release}]"
},
{
"type": "uptime",
"key": "{#90}│ {#93}Uptime {#90}│",
"format": "{$1}{?days}{days} Days + {?}{hours}:{minutes}:{seconds}"
},
{
"type": "cpu",
"key": "{#90}│ {#91}CPU {#90}│",
"showPeCoreCount": true,
"temp": true,
"format": "{$1}{name} {#2}[C:{core-types}] [{freq-max}]"
},
{
"type": "gpu",
"key": "{#90}│ {#91}GPU {#90}│",
"detectionMethod": "auto",
"driverSpecific": true,
"format": "{$1}{name} {#2}[C:{core-count}]{?frequency} [{frequency}]{?} {#2}[{type}]"
},
{
"type": "memory",
"key": "{#90}│ {#91}Memory {#90}│",
"format": "{$1}{used} / {total} ({percentage})"
},
{
"type": "disk",
"key": "{#90}│ {#91}Disk {#90}│",
"format": "{$1}{size-used} / {size-total} ({size-percentage})"
},
{
"type": "poweradapter",
"key": "{#90}│ {#91}Power {#90}│",
"format": "{$1}{name}"
},
{
"type": "terminal",
"key": "{#90}│ {#95}Terminal {#90}│",
"format": "{$1}{pretty-name} {#2}[{version}] [PID:{pid}]"
},
{
"type": "terminalfont",
"key": "{#90}│ {#95}Font {#90}│",
"format": "{$1}{name} {#2}[{size}]"
},
{
"type": "shell",
"key": "{#90}│ {#95}Shell {#90}│",
"format": "{$1}{pretty-name} {#2}[v{version}] [PID:{pid}]"
},
{
// localip IPv4
"type": "localip",
"key": "{#90}│ {#94}Local IPv4 {#90}│",
"showPrefixLen": true,
"showIpv4": true,
"showIpv6": false,
"showMtu": true,
"format": "{$1}{ifname}: {ipv4} {#2}[MTU:{mtu}]"
},
{
// localip IPv6
"type": "localip",
"key": "{#90}│ {#94}Local IPv6 {#90}│",
"showPrefixLen": true,
"showIpv4": false,
"showIpv6": true,
"showMtu": true,
"format": "{$1}{ifname}: {ipv6} {#2}[MTU:{mtu}]"
},
{
"type": "publicip",
"key": "{#90}│ {#94}Public IPv4 {#90}│",
"ipv6": false,
"format": "{$1}{ip} {#2}[{location}]"
},
{
"type": "publicip",
"key": "{#90}│ {#94}Public IPv6 {#90}│",
"ipv6": true,
"format": "{$1}{ip} {#2}[{location}]"
},
// CUSTOM - Button UI bar
{
"type": "custom",
"key": "{#90}╰─────────────╯",
"format": "{#90}╰────────────────────────────────────────────────────────────╯",
},
"break",
{
"type": "custom",
"key": " ",
"format": "{#90}╭ Colors ───────────────────────────────────────────────────────────────────╮",
},
{
"type": "custom",
"format": "{#90}│ {#40} {#41} {#42} {#43} {#44} {#45} {#46} {#47} {#} {#90}│",
},
{
"type": "custom",
"format": "{#90}│ {#100} {#101} {#102} {#103} {#104} {#105} {#106} {#107} {#} {#90}│",
},
{
"type": "custom",
"format": "{#90}╰───────────────────────────────────────────────────────────────────────────╯",
},
]
}
+49
View File
@@ -0,0 +1,49 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "small",
"padding": {
"top": 1
}
},
"display": {
"separator": " "
},
"modules": [
"break",
"title",
{
"type": "os",
"key": "os ",
"keyColor": "red"
},
{
"type": "kernel",
"key": "kernel",
"keyColor": "green"
},
{
"type": "host",
"format": "{vendor} {family}",
"key": "host ",
"keyColor": "yellow"
},
{
"type": "packages",
"key": "pkgs ",
"keyColor": "blue"
},
{
"type": "uptime",
"format": "{?days}{days}d {?}{hours}h {minutes}m",
"key": "uptime",
"keyColor": "magenta"
},
{
"type": "memory",
"key": "memory",
"keyColor": "cyan"
},
"break"
]
}
+63
View File
@@ -0,0 +1,63 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "small"
},
"display": {
"separator": " ",
"key": {
"type": "both"
},
"bar": {
"border": {
"left": "\uee00",
"leftElapsed": "\uee03",
"right": "\uee02",
"rightElapsed": "\uee05"
},
"char": {
"total": "\uee01",
"elapsed": "\uee04"
},
"color": {
"total": null
}
},
"percent": {
"type": [
"bar",
"bar-monochrome"
]
}
},
"modules": [
"title",
"separator",
{
"type": "memory",
"key": "MEM"
},
{
"type": "swap",
"key": "SWP"
},
{
"type": "disk",
"folders": "/",
"key": "DSK"
},
{
"type": "battery",
"key": "BAT"
},
{
"type": "brightness",
"key": "BGT"
},
{
"type": "colors",
"paddingLeft": 6,
"symbol": "circle"
}
]
}
+136
View File
@@ -0,0 +1,136 @@
// #1887
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": null,
"display": {
"constants": [
"\u001b[s\u001b[33C│\u001b[u",
" » "
],
"separator": "",
"percent": {
"type": ["num", "bar"]
},
"brightColor": false,
"bar": {
"border": {
"left": "[",
"leftElapsed": "[",
"right": "]",
"rightElapsed": "]"
},
"char": {
"elapsed": "─",
"total": "─"
},
"color": {
"elapsed": "default",
"total": "light_black"
},
"width": 16
},
"color": {
"separator": "default",
"keys": "default",
"output": "default"
}
},
"modules": [
"title",
{
"type": "custom",
"format": "┌────「 {#1}OS{#} 」────────────────────────────┐"
},
{
"type": "os",
"key": "│ {icon}{$2}{$1}"
},
{
"type": "disk",
"folders": "/",
"key": "│ {$1}",
"format": "{size-percentage-bar} {size-percentage}"
},
{
"type": "disk",
"folders": "/",
"key": "│ {$1}",
"format": "{size-used} / {size-total}"
},
{
"type": "custom",
"format": "└────────────────────────────────────────┘"
},
"break",
{
"type": "custom",
"format": "┌────「 {#1}UI{#} 」────────────────────────────┐"
},
{
"type": "wm",
"key": "│ {icon}{$2}{$1}"
},
{
"type": "wmtheme",
"key": "│ {icon}{$2}{$1}"
},
{
"type": "custom",
"key": "│ {$1}"
},
{
"type": "display",
"key": "│ {icon}{$2}{$1}",
"format": "{width}x{height} @ {refresh-rate} Hz"
},
{
"type": "custom",
"key": "│ {$1}"
},
{
"type": "terminal",
"key": "│ {icon}{$2}{$1}"
},
{
"type": "terminalfont",
"key": "│ {icon}{$2}{$1}"
},
{
"type": "custom",
"format": "└────────────────────────────────────────┘"
},
"break",
{
"type": "custom",
"format": "┌────「 {#1}HW{#} 」────────────────────────────┐"
},
{
"type": "cpu",
"key": "│ {icon}{$2}{$1}",
"format": "{name}"
},
{
"type": "gpu",
"key": "│ {icon}{$2}{$1}",
"format": "{name}"
},
{
"type": "custom",
"key": "│ {$1}"
},
{
"type": "memory",
"key": "│ {icon}{$2}{$1}",
"format": "{percentage-bar} {percentage}"
},
{
"type": "memory",
"key": "│ {$1}",
"format": "{used} / {total}"
},
{
"type": "custom",
"format": "└────────────────────────────────────────┘"
}
]
}
+87
View File
@@ -0,0 +1,87 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": null,
"display": {
"key": {
"type": "both",
"paddingLeft": 6,
"width": 17
}
},
"modules": [
{
"type": "custom",
"format": "|---------------------: {#1}Hardware{#} : ---------------------|"
},
"break",
{
"keyColor": "green",
"type": "host"
},
{
"keyColor": "green",
"type": "cpu"
},
{
"keyColor": "yellow",
"type": "memory"
},
{
"keyColor": "yellow",
"type": "swap"
},
{
"type": "custom",
"keyIcon": "",
"key": "Disks"
},
{
"type": "disk",
"key": " ",
"format": " [{mountpoint}] - {size-used} / {size-total} ({size-percentage})"
},
"break",
{
"type": "title",
"format": "|-------------------------------------------------------|\u001b[40D: {#1}{user-name} @ {host-name}{#} :"
},
"break",
{
"type": "os",
"keyColor": "cyan"
},
{
"type": "kernel",
"keyColor": "cyan"
},
{
"type": "packages",
"keyColor": "red",
"key": "Pkgs"
},
{
"type": "shell",
"keyColor": "red"
},
{
"type": "terminal",
"key": "Term",
"keyColor": "red"
},
{
"type": "locale",
"keyColor": "magenta"
},
"break",
{
"type": "custom",
"format": "|---------------------: {#1}Software{#} : ---------------------|"
},
"break",
{
"type": "colors",
"symbol": "circle",
"paddingLeft": 8
}
]
}
+4 -2
View File
@@ -8,8 +8,10 @@
"width": 11
},
"bar": {
"charElapsed": "=",
"charTotal": "-",
"char": {
"elapsed": "=",
"total": "-"
},
"width": 13
},
"percent": {
+13 -4
View File
@@ -3,7 +3,12 @@
"display": {
"size": {
"maxPrefix": "MB",
"ndigits": 0
"ndigits": 0,
"spaceBeforeUnit": "never"
},
"freq": {
"ndigits": 3,
"spaceBeforeUnit": "never"
}
},
"modules": [
@@ -16,7 +21,10 @@
"format": "{release}"
},
"uptime",
"packages",
{
"type": "packages",
"combined": true
},
"shell",
{
"type": "display",
@@ -36,11 +44,12 @@
"cpu",
{
"type": "gpu",
"key": "GPU"
"key": "GPU",
"format": "{name}"
},
{
"type": "memory",
"format": "{} / {}"
"format": "{used} / {total}"
},
"break",
"colors"
+121 -52
View File
@@ -1,11 +1,15 @@
#!/usr/bin/env python3
"""
Python script to generate a man page for the command `fastfetch`.
The man content will be printed to stdout so you will need to
pipe it to a file if you want to save it.
The command options will be generated using a JSON file.
For the format of the JSON file, see https://github.com/fastfetch-cli/fastfetch/blob/dev/src/data/help.json
Python script to generate a comprehensive man page for the command `fastfetch`.
The generated man page content will be printed to stdout,
so you will need to pipe it to a file if you want to save it.
Example: python3 gen-man.py > fastfetch.1
The command options are generated using a JSON file.
For the JSON file format, see:
https://github.com/fastfetch-cli/fastfetch/blob/dev/src/data/help.json
"""
from json import load
@@ -33,7 +37,7 @@ pathToHelpFile = path.join(pathToCurrentDir, "../src/data/help.json")
# man page section
manSection = 1
# title (center header)
titlePage = "Fastfetch man page"
titlePage = "FASTFETCH"
# date (center footer)
# format : "Month (abbreviation) Day Year"
todayDate = datetime.fromtimestamp(
@@ -47,81 +51,118 @@ pathToVersionFile = path.join(pathToCurrentDir, "../CMakeLists.txt")
###### Sections Text ######
# text displayed in the "NAME" section
nameSection = r"fastfetch \- A maintained, feature\-rich and performance oriented, neofetch like system information tool"
nameSection = r"fastfetch \- A fast and feature-rich system information tool similar to neofetch"
# text displayed in the "DESCRIPTION" section
descriptionSection = r"""
Fastfetch is a tool for displaying system information in a visually appealing way. Written primarily in C, it focuses on performance and customizability while providing functionality similar to neofetch.
It supports Linux, Android, FreeBSD, macOS, and Windows 7 or newer.
"""
# text displayed at the beginning of the "OPTIONS" section
optionSection = r"""
Parsing is not case sensitive. E.g. \fB--logo-type\fR is
equal to \fB--LOGO-TYPE\fR.
Options are parsed in a case-insensitive manner. For example, \fB--logo-type\fR and \fB--LOGO-TYPE\fR are treated identically.
If a value is between square brackets, it is optional.
An optional boolean value defaults to true if not specified.
Arguments in square brackets are optional. Optional boolean arguments default to 'true' when specified without a value.
More detailed help messages for each options can be printed
with \fB-h <option_without_dash_prefix>\fR.
For more detailed information about a specific option, use:
\fBfastfetch -h <option_name_without_dashes>\fR
All options can be made permanent with command
\fBfastfetch <options> --gen-config\fR.
Any combination of options can be made permanent by generating a configuration file:
\fBfastfetch <options> --gen-config\fR
"""
# text displayed in the "CONFIGURATION"
configurationSection = f"""
.SS Fetch Structure
The structure of a fetch describes the modules that should
be included in the output. It consists of a string of modules,
separated by a colon (:). To list all available modules,
use --list-modules.
The structure defines which modules to display and in what order. It consists of module names separated by colons (:).
For example: {startBold}title:separator:os:kernel:uptime{endBold}
To list all available modules, use {startBold}--list-modules{endBold}
.SS Config Files
Fastfetch uses JSONC based format for configuration.
Fastfetch doesn't generate config file automatically;
it should be generated manually by {startBold}--gen-config{endBold}.
The config file will be saved in
{startBold}~/.config/fastfetch/config.jsonc{endBold} by default.
Fastfetch uses JSONC (JSON with Comments) for configuration files. These files must have the .jsonc extension.
A JSONC config file is a JSON file that also supports comments
with (// and /* */). Those files must have the extension '.jsonc'.
You can generate a default config file using {startBold}--gen-config{endBold}. By default, the config file is saved at {startBold}~/.config/fastfetch/config.jsonc{endBold}.
The specified configuration/preset files are searched in the following order:
The configuration/preset files are searched in the following locations (in order):
{startBold}1.{endBold} relative to the current working directory
{startBold}1.{endBold} Relative to the current working directory
{startBold}2.{endBold} relative to ~/.local/share/fastfetch/presets/
{startBold}2.{endBold} Relative to ~/.local/share/fastfetch/presets/
{startBold}3.{endBold} relative to /usr/share/fastfetch/presets/
{startBold}3.{endBold} Relative to /usr/share/fastfetch/presets/
Fastfetch provides some default presets. List them with --list-presets.
For detailed information on logo options, module configuration, and formatting, visit:
{startBold}https://github.com/fastfetch-cli/fastfetch/wiki/Configuration{endBold}
Fastfetch provides several built-in presets. List them with {startBold}--list-presets{endBold}.
.SS JSON Schema
A JSON schema is available for editor intelligence when editing the configuration file. Add the following line at the beginning of your config file:
{startBold}"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json"{endBold}
"""
# text displayed in the "EXAMPLE" section
exampleSection = """
.SS Config files:
exampleSection = f"""
.SS Basic Usage
{startBold}fastfetch{endBold}
.SS Use a specific logo
{startBold}fastfetch --logo arch{endBold}
.SS Custom structure
{startBold}fastfetch --structure title:os:kernel:uptime:memory{endBold}
.SS Generate a config file
{startBold}fastfetch --gen-config{endBold}
.SS Use a preset
{startBold}fastfetch --config neofetch{endBold}
.SS Config File Example
.nf
// ~/.config/fastfetch/config.jsonc
{
{{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {{
"type": "auto",
"source": "arch"
}},
"display": {{
"separator": ": ",
"color": {{
"keys": "blue",
"title": "red"
}},
"key": {{
"width": 12
}}
}},
"modules": [
"title",
"separator",
"module1",
{
"type": "module2",
"module2-option": "value"
}
"os",
"kernel",
"uptime",
{{
"type": "memory",
"format": "{{used}}/{{total}} ({{used_percent}}%)"
}}
]
}
}}
.fi
"""
# text displayed in the "BUGS" section
bugSection = "Please report bugs to : \
https://github.com/fastfetch-cli/fastfetch/issues"
bugSection = "Please report bugs to: https://github.com/fastfetch-cli/fastfetch/issues"
# text displayed in the "WIKI" section
wikiSection = "Fastfetch github wiki : https://github.com/fastfetch-cli/fastfetch/wiki/Configuration"
# text displayed in the "AUTHORS" section
authorsSection = "Fastfetch is developed by a team of contributors on GitHub.\nVisit https://github.com/fastfetch-cli/fastfetch for more information."
###### Argument decoration ######
@@ -130,7 +171,7 @@ wikiSection = "Fastfetch github wiki : https://github.com/fastfetch-cli/fastfetc
# if an optional argument is displayed as [?optArg] (with "optArg" underlined)
# this value should be f"[?{startUnderline}"
startOptionalArgument = f"[{startUnderline}?"
startOptionalArgument = f"[{startUnderline}"
# if an optional argument is displayed as [?optArg] (with "optArg underlined")
# this value should be f"{endUnderline}]"
endOptionalArgument = f"{endUnderline}]"
@@ -161,7 +202,7 @@ def main():
for line in versionFile:
researchVersion = search(r"^\s*VERSION (\d+\.\d+\.\d+)$", line)
if (researchVersion):
print(f"\"{researchVersion.group(1)}\"", end=" ")
print(f"\"Fastfetch {researchVersion.group(1)}\"", end=" ")
break
print(f"\"{titlePage}\"")
@@ -177,13 +218,13 @@ def main():
print(".SH SYNOPSIS")
print(".B fastfetch")
print(f"[{startUnderline}OPTIONS{endUnderline}]")\
print(f"[{startUnderline}OPTIONS{endUnderline}...]")
###### Wiki ######
###### Description ######
print(".SH WIKI")
print(wikiSection)
print(".SH DESCRIPTION")
print(descriptionSection)
###### Configuration ######
@@ -202,7 +243,7 @@ def main():
for key, value in helpFileData.items():
# print new subsection
print(f".SS {key}:")
print(f".SS {key}")
# loop through every option in a section
for option in value:
@@ -237,7 +278,25 @@ def main():
print(startMandatoryArgument + option['arg']['type'] + endMandatoryArgument, end="")
# description
print(f"\n {option['desc']} \n")
print()
# If desc is a list, join with newlines and proper spacing
if isinstance(option['desc'], list):
desc_text = "\n ".join(option['desc'])
print(f" {desc_text}")
else:
print(f" {option['desc']}")
# Add remarks if available
if "remark" in keyList:
print()
if isinstance(option['remark'], list):
for remark in option['remark']:
print(f" {remark}")
else:
print(f" {option['remark']}")
print()
###### Examples ######
@@ -246,12 +305,22 @@ def main():
print(exampleSection)
###### See Also ######
print(".SH \"SEE ALSO\"")
print(".BR neofetch (1)")
###### Bugs ######
print(".SH BUGS")
print(bugSection)
###### Authors ######
print(".SH AUTHORS")
print(authorsSection)
if __name__ == "__main__":
-383
View File
@@ -1,383 +0,0 @@
//
// Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.
//
/// \file
/// \mainpage
/// AGS Library Overview
/// --------------------
/// This document provides an overview of the AGS (AMD GPU Services) library. The AGS library provides software developers with the ability to query
/// AMD GPU software and hardware state information that is not normally available through standard operating systems or graphic APIs.
///
/// The latest version of the API is publicly hosted here: https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/.
/// It is also worth checking http://gpuopen.com/gaming-product/amd-gpu-services-ags-library/ for any updates and articles on AGS.
/// \internal
/// Online documentation is publicly hosted here: http://gpuopen-librariesandsdks.github.io/ags/
/// \endinternal
///
/// ---------------------------------------
/// What's new in AGS 6.2 since version 6.1
/// ---------------------------------------
/// AGS 6.2 includes the following updates:
/// * Shader clock intrinsics
/// * Minor improvements and fixes
///
/// ---------------------------------------
/// What's new in AGS 6.1 since version 6.0
/// ---------------------------------------
/// AGS 6.1 includes the following updates:
/// * RDNA3 detection
///
/// ---------------------------------------
/// What's new in AGS 6.0 since version 5.4.2
/// ---------------------------------------
/// AGS 6.0 includes the following updates:
/// * DX12 ray tracing hit token for RDNA2 hardware.
/// * Shader intrinsic that exposes ReadLaneAt in DX12.
/// * Shader intrinsics that expose explicit float conversions in DX12.
/// * Refactored and revised API to minimize user error.
/// * Added agsGetVersionNumber.
/// * Detection for external GPUs.
/// * Detection of RDNA2 architecture.
/// * Grouped the more established intrinsics together into per year support.
/// * Function pointer typedefs for the API
///
/// ---------------------------------------
/// What's new in AGS 5.4.2 since version 5.4.1
/// ---------------------------------------
/// AGS 5.4.2 includes the following updates:
/// * sharedMemoryInBytes has been reinstated.
/// * Clock speed returned for APUs.
///
/// ---------------------------------------
/// What's new in AGS 5.4.1 since version 5.4.0
/// ---------------------------------------
/// AGS 5.4.1 includes the following updates:
/// * AsicFamily_Count to help with code maintenance.
/// * Visual Studio 2019 support.
/// * x86 support
/// * BaseInstance and BaseVertex intrinsics along with corresponding caps bits.
/// * GetWaveSize intrinsic along with corresponding caps bits.
///
/// ---------------------------------------
/// What's new in AGS 5.4 since version 5.3
/// ---------------------------------------
/// AGS 5.4 includes the following updates:
/// * A more detailed description of the GPU architecture, now including RDNA GPUs.
/// * Radeon 7 core and memory speeds returned.
/// * Draw index and Atomic U64 intrinsics for both DX11 and DX12.
///
/// ---------------------------------------
/// What's new in AGS 5.3 since version 5.2
/// ---------------------------------------
/// AGS 5.3 includes the following updates:
/// * DX11 deferred context support for Multi Draw Indirect and UAV Overlap extensions.
/// * A Radeon Software Version helper to determine whether the installed driver meets your game's minimum driver version requirements.
/// * Freesync HDR Gamma 2.2 mode which uses a 1010102 swapchain and can be considered as an alternative to using the 64 bit swapchain required for Freesync HDR scRGB.
///
/// Using the AGS library
/// ---------------------
/// It is recommended to take a look at the source code for the samples that come with the AGS SDK:
/// * AGSSample
/// * CrossfireSample
/// * EyefinitySample
/// The AGSSample application is the simplest of the three examples and demonstrates the code required to initialize AGS and use it to query the GPU and Eyefinity state.
/// The CrossfireSample application demonstrates the use of the new API to transfer resources on GPUs in Crossfire mode. Lastly, the EyefinitySample application provides a more
/// extensive example of Eyefinity setup than the basic example provided in AGSSample.
/// There are other samples on Github that demonstrate the DirectX shader extensions, such as the Barycentrics11 and Barycentrics12 samples.
///
/// To add AGS support to an existing project, follow these steps:
/// * Link your project against the correct import library. Choose from either the 32 bit or 64 bit version.
/// * Copy the AGS dll into the same directory as your game executable.
/// * Include the amd_ags.h header file from your source code.
/// * Include the AGS hlsl files if you are using the shader intrinsics.
/// * Declare a pointer to an AGSContext and make this available for all subsequent calls to AGS.
/// * On game initialization, call \ref agsInitialize passing in the address of the context. On success, this function will return a valid context pointer.
///
/// Don't forget to cleanup AGS by calling \ref agsDeInitialize when the app exits, after the device has been destroyed.
#ifndef AMD_AGS_H
#define AMD_AGS_H
#define AMD_AGS_VERSION_MAJOR 6 ///< AGS major version
#define AMD_AGS_VERSION_MINOR 2 ///< AGS minor version
#define AMD_AGS_VERSION_PATCH 0 ///< AGS patch version
#ifdef __cplusplus
extern "C" {
#endif
/// \defgroup Defines AGS defines
/// @{
#if defined (AGS_GCC)
#define AMD_AGS_API
#else
#define AMD_AGS_API __declspec(dllexport) ///< AGS exported functions
#endif
#define AGS_MAKE_VERSION( major, minor, patch ) ( ( major << 22 ) | ( minor << 12 ) | patch ) ///< Macro to create the app and engine versions for the fields in \ref AGSDX12ExtensionParams and \ref AGSDX11ExtensionParams and the Radeon Software Version
#define AGS_UNSPECIFIED_VERSION 0xFFFFAD00 ///< Use this to specify no version
#define AGS_CURRENT_VERSION AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ) ///< Macro to return the current AGS version as defined by the AGS header file
/// @}
/// \defgroup enums General enumerations
/// @{
/// The return codes
typedef enum AGSReturnCode
{
AGS_SUCCESS, ///< Successful function call
AGS_FAILURE, ///< Failed to complete call for some unspecified reason
AGS_INVALID_ARGS, ///< Invalid arguments into the function
AGS_OUT_OF_MEMORY, ///< Out of memory when allocating space internally
AGS_MISSING_D3D_DLL, ///< Returned when a D3D dll fails to load
AGS_LEGACY_DRIVER, ///< Returned if a feature is not present in the installed driver
AGS_NO_AMD_DRIVER_INSTALLED, ///< Returned if the AMD GPU driver does not appear to be installed
AGS_EXTENSION_NOT_SUPPORTED, ///< Returned if the driver does not support the requested driver extension
AGS_ADL_FAILURE, ///< Failure in ADL (the AMD Display Library)
AGS_DX_FAILURE, ///< Failure from DirectX runtime
AGS_D3DDEVICE_NOT_CREATED ///< Failure due to not creating the D3D device successfully via AGS.
} AGSReturnCode;
/// @}
typedef struct AGSContext AGSContext; ///< All function calls in AGS require a pointer to a context. This is generated via \ref agsInitialize
/// The rectangle struct used by AGS.
typedef struct AGSRect
{
int offsetX; ///< Offset on X axis
int offsetY; ///< Offset on Y axis
int width; ///< Width of rectangle
int height; ///< Height of rectangle
} AGSRect;
/// The display info struct used to describe a display enumerated by AGS
typedef struct AGSDisplayInfo
{
char name[ 256 ]; ///< The name of the display
char displayDeviceName[ 32 ]; ///< The display device name, i.e. DISPLAY_DEVICE::DeviceName
unsigned int isPrimaryDisplay : 1; ///< Whether this display is marked as the primary display
unsigned int HDR10 : 1; ///< HDR10 is supported on this display
unsigned int dolbyVision : 1; ///< Dolby Vision is supported on this display
unsigned int freesync : 1; ///< Freesync is supported on this display
unsigned int freesyncHDR : 1; ///< Freesync HDR is supported on this display
unsigned int eyefinityInGroup : 1; ///< The display is part of the Eyefinity group
unsigned int eyefinityPreferredDisplay : 1; ///< The display is the preferred display in the Eyefinity group for displaying the UI
unsigned int eyefinityInPortraitMode : 1; ///< The display is in the Eyefinity group but in portrait mode
unsigned int reservedPadding : 24; ///< Reserved for future use
int maxResolutionX; ///< The maximum supported resolution of the unrotated display
int maxResolutionY; ///< The maximum supported resolution of the unrotated display
float maxRefreshRate; ///< The maximum supported refresh rate of the display
AGSRect currentResolution; ///< The current resolution and position in the desktop, ignoring Eyefinity bezel compensation
AGSRect visibleResolution; ///< The visible resolution and position. When Eyefinity bezel compensation is enabled this will
///< be the sub region in the Eyefinity single large surface (SLS)
float currentRefreshRate; ///< The current refresh rate
int eyefinityGridCoordX; ///< The X coordinate in the Eyefinity grid. -1 if not in an Eyefinity group
int eyefinityGridCoordY; ///< The Y coordinate in the Eyefinity grid. -1 if not in an Eyefinity group
double chromaticityRedX; ///< Red display primary X coord
double chromaticityRedY; ///< Red display primary Y coord
double chromaticityGreenX; ///< Green display primary X coord
double chromaticityGreenY; ///< Green display primary Y coord
double chromaticityBlueX; ///< Blue display primary X coord
double chromaticityBlueY; ///< Blue display primary Y coord
double chromaticityWhitePointX; ///< White point X coord
double chromaticityWhitePointY; ///< White point Y coord
double screenDiffuseReflectance; ///< Percentage expressed between 0 - 1
double screenSpecularReflectance; ///< Percentage expressed between 0 - 1
double minLuminance; ///< The minimum luminance of the display in nits
double maxLuminance; ///< The maximum luminance of the display in nits
double avgLuminance; ///< The average luminance of the display in nits
int logicalDisplayIndex; ///< The internally used index of this display
int adlAdapterIndex; ///< The internally used ADL adapter index
int reserved; ///< reserved field
} AGSDisplayInfo;
/// The ASIC family
typedef enum AsicFamily
{
AsicFamily_Unknown, ///< Unknown architecture, potentially from another IHV. Check \ref AGSDeviceInfo::vendorId
AsicFamily_PreGCN, ///< Pre GCN architecture.
AsicFamily_GCN1, ///< AMD GCN 1 architecture: Oland, Cape Verde, Pitcairn & Tahiti.
AsicFamily_GCN2, ///< AMD GCN 2 architecture: Hawaii & Bonaire. This also includes APUs Kaveri and Carrizo.
AsicFamily_GCN3, ///< AMD GCN 3 architecture: Tonga & Fiji.
AsicFamily_GCN4, ///< AMD GCN 4 architecture: Polaris.
AsicFamily_Vega, ///< AMD Vega architecture, including Raven Ridge (ie AMD Ryzen CPU + AMD Vega GPU).
AsicFamily_RDNA, ///< AMD RDNA architecture
AsicFamily_RDNA2, ///< AMD RDNA2 architecture
AsicFamily_RDNA3, ///< AMD RDNA3 architecture
AsicFamily_Count ///< Number of enumerated ASIC families
} AsicFamily;
/// The device info struct used to describe a physical GPU enumerated by AGS
typedef struct AGSDeviceInfo
{
const char* adapterString; ///< The adapter name string
AsicFamily asicFamily; ///< Set to Unknown if not AMD hardware
unsigned int isAPU : 1; ///< Whether this device is an APU
unsigned int isPrimaryDevice : 1; ///< Whether this device is marked as the primary device
unsigned int isExternal :1; ///< Whether this device is a detachable, external device
unsigned int reservedPadding : 29; ///< Reserved for future use
int vendorId; ///< The vendor id
int deviceId; ///< The device id
int revisionId; ///< The revision id
int numCUs; ///< Number of compute units
int numWGPs; ///< Number of RDNA Work Group Processors. Only valid if ASIC is RDNA onwards.
int numROPs; ///< Number of ROPs
int coreClock; ///< Core clock speed at 100% power in MHz
int memoryClock; ///< Memory clock speed at 100% power in MHz
int memoryBandwidth; ///< Memory bandwidth in MB/s
float teraFlops; ///< Teraflops of GPU. Zero if not GCN onwards. Calculated from iCoreClock * iNumCUs * 64 Pixels/clk * 2 instructions/MAD
unsigned long long localMemoryInBytes; ///< The size of local memory in bytes. 0 for non AMD hardware.
unsigned long long sharedMemoryInBytes; ///< The size of system memory available to the GPU in bytes. It is important to factor this into your VRAM budget for APUs
///< as the reported local memory will only be a small fraction of the total memory available to the GPU.
int numDisplays; ///< The number of active displays found to be attached to this adapter.
AGSDisplayInfo* displays; ///< List of displays allocated by AGS to be numDisplays in length.
int eyefinityEnabled; ///< Indicates if Eyefinity is active
int eyefinityGridWidth; ///< Contains width of the multi-monitor grid that makes up the Eyefinity Single Large Surface.
int eyefinityGridHeight; ///< Contains height of the multi-monitor grid that makes up the Eyefinity Single Large Surface.
int eyefinityResolutionX; ///< Contains width in pixels of the multi-monitor Single Large Surface.
int eyefinityResolutionY; ///< Contains height in pixels of the multi-monitor Single Large Surface.
int eyefinityBezelCompensated; ///< Indicates if bezel compensation is used for the current SLS display area. 1 if enabled, and 0 if disabled.
int adlAdapterIndex; ///< Internally used index into the ADL list of adapters
int reserved; ///< reserved field
} AGSDeviceInfo;
/// \defgroup general General API functions
/// API for initialization, cleanup, HDR display modes and Crossfire GPU count
/// @{
typedef void* (__stdcall *AGS_ALLOC_CALLBACK)( size_t allocationSize ); ///< AGS user defined allocation prototype
typedef void (__stdcall *AGS_FREE_CALLBACK)( void* allocationPtr ); ///< AGS user defined free prototype
/// The configuration options that can be passed in to \ref agsInitialize
typedef struct AGSConfiguration
{
AGS_ALLOC_CALLBACK allocCallback; ///< Optional memory allocation callback. If not supplied, malloc() is used
AGS_FREE_CALLBACK freeCallback; ///< Optional memory freeing callback. If not supplied, free() is used
} AGSConfiguration;
/// The top level GPU information returned from \ref agsInitialize
typedef struct AGSGPUInfo
{
const char* driverVersion; ///< The AMD driver package version
const char* radeonSoftwareVersion; ///< The Radeon Software Version
int numDevices; ///< Number of GPUs in the system
AGSDeviceInfo* devices; ///< List of GPUs in the system
} AGSGPUInfo;
/// The struct to specify the display settings to the driver.
typedef struct AGSDisplaySettings AGSDisplaySettings;
/// The result returned from \ref agsCheckDriverVersion
typedef enum AGSDriverVersionResult
{
AGS_SOFTWAREVERSIONCHECK_OK, ///< The reported Radeon Software Version is newer or the same as the required version
AGS_SOFTWAREVERSIONCHECK_OLDER, ///< The reported Radeon Software Version is older than the required version
AGS_SOFTWAREVERSIONCHECK_UNDEFINED ///< The check could not determine as result. This could be because it is a private or custom driver or just invalid arguments.
} AGSDriverVersionResult;
///
/// Helper function to check the installed software version against the required software version.
///
/// \param [in] radeonSoftwareVersionReported The Radeon Software Version returned from \ref AGSGPUInfo::radeonSoftwareVersion.
/// \param [in] radeonSoftwareVersionRequired The Radeon Software Version to check against. This is specificed using \ref AGS_MAKE_VERSION.
/// \return The result of the check.
///
AMD_AGS_API AGSDriverVersionResult agsCheckDriverVersion( const char* radeonSoftwareVersionReported, unsigned int radeonSoftwareVersionRequired );
///
/// Function to return the AGS version number.
///
/// \return The version number made using AGS_MAKE_VERSION( AMD_AGS_VERSION_MAJOR, AMD_AGS_VERSION_MINOR, AMD_AGS_VERSION_PATCH ).
///
AMD_AGS_API int agsGetVersionNumber();
///
/// Function used to initialize the AGS library.
/// agsVersion must be specified as AGS_CURRENT_VERSION or the call will return \ref AGS_INVALID_ARGS.
/// Must be called prior to any of the subsequent AGS API calls.
/// Must be called prior to ID3D11Device or ID3D12Device creation.
/// \note The caller of this function should handle the possibility of the call failing in the cases below. One option is to do a vendor id check and only call \ref agsInitialize if there is an AMD GPU present.
/// \note This function will fail with \ref AGS_NO_AMD_DRIVER_INSTALLED if there is no AMD driver found on the system.
/// \note This function will fail with \ref AGS_LEGACY_DRIVER in Catalyst versions before 12.20.
///
/// \param [in] agsVersion The API version specified using the \ref AGS_CURRENT_VERSION macro. If this does not match the version in the binary this initialization call will fail.
/// \param [in] config Optional pointer to a AGSConfiguration struct to override the default library configuration.
/// \param [out] context Address of a pointer to a context. This function allocates a context on the heap which is then required for all subsequent API calls.
/// \param [out] gpuInfo Optional pointer to a AGSGPUInfo struct which will get filled in for all the GPUs in the system.
///
AMD_AGS_API AGSReturnCode agsInitialize( int agsVersion, const AGSConfiguration* config, AGSContext** context, AGSGPUInfo* gpuInfo );
///
/// Function used to clean up the AGS library.
///
/// \param [in] context Pointer to a context. This function will deallocate the context from the heap.
///
AMD_AGS_API AGSReturnCode agsDeInitialize( AGSContext* context );
///
/// Function used to set a specific display into HDR mode
/// \note Setting all of the values apart from color space and transfer function to zero will cause the display to use defaults.
/// \note Call this function after each mode change (switch to fullscreen, any change in swapchain etc).
/// \note HDR10 PQ mode requires a 1010102 swapchain.
/// \note HDR10 scRGB mode requires an FP16 swapchain.
/// \note Freesync HDR scRGB mode requires an FP16 swapchain.
/// \note Freesync HDR Gamma 2.2 mode requires a 1010102 swapchain.
/// \note Dolby Vision requires a 8888 UNORM swapchain.
///
/// \param [in] context Pointer to a context. This is generated by \ref agsInitialize
/// \param [in] deviceIndex The index of the device listed in \ref AGSGPUInfo::devices.
/// \param [in] displayIndex The index of the display listed in \ref AGSDeviceInfo::displays.
/// \param [in] settings Pointer to the display settings to use.
///
AMD_AGS_API AGSReturnCode agsSetDisplayMode( AGSContext* context, int deviceIndex, int displayIndex, const AGSDisplaySettings* settings );
/// @}
/// @}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AMD_AGS_H
-7
View File
@@ -1,7 +0,0 @@
{
"home": "https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK",
"license": "MIT (embeded in source)",
"version": "AGS v6.2.0",
"author": "Advanced Micro Devices, Inc",
"modified": "CarterLi"
}
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
//
// Copyright (c) 2016 - 2022 Advanced Micro Devices, Inc. All rights reserved.
//
// 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.
/// \file adl_sdk.h
/// \brief Contains the definition of the Memory Allocation Callback.\n <b>Included in ADL SDK</b>
///
/// \n\n
/// This file contains the definition of the Memory Allocation Callback.\n
/// It also includes definitions of the respective structures and constants.\n
/// <b> This is the only header file to be included in a C/C++ project using ADL </b>
#ifndef ADL_SDK_H_
#define ADL_SDK_H_
#include "adl_structures.h"
#if defined (LINUX)
#define __stdcall
#endif /* (LINUX) */
/// Memory Allocation Call back
typedef void* ( __stdcall *ADL_MAIN_MALLOC_CALLBACK )( int );
#define ADL_SDK_MAJOR_VERSION 17
#define ADL_SDK_MINOR_VERSION 1
#endif /* ADL_SDK_H_ */
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
{
"home": "https://github.com/GPUOpen-LibrariesAndSDKs/display-library",
"license": "MIT (embeded in source)",
"version": "ADL SDK 17.1",
"author": "Advanced Micro Devices, Inc"
}
-7
View File
@@ -1,7 +0,0 @@
{
"home": "https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c",
"license": "MIT compatible (embed in source)",
"version": "2007-05-26 (Unicode 5.0)",
"author": "Markus Kuhn",
"modified": "CarterLi"
}
-314
View File
@@ -1,314 +0,0 @@
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in this area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute this software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to this software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
#include <wchar.h>
struct interval {
int first;
int last;
};
/* auxiliary function for binary search in interval table */
static int bisearch(wchar_t ucs, const struct interval *table, int max) {
int min = 0;
int mid;
if (ucs < table[0].first || ucs > table[max].last)
return 0;
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
/* The following two functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - SOFT HYPHEN (U+00AD) has a column width of 1.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* Full-width (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that wchar_t characters are encoded
* in ISO 10646.
*/
int mk_wcwidth(wchar_t ucs)
{
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
static const struct interval combining[] = {
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
{ 0xE0100, 0xE01EF }
};
/* test for 8-bit control characters */
if (ucs == 0)
return 0;
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
return -1;
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1))
return 0;
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
#ifndef _WIN32 // sizeof(wchar_t) == 2
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd) ||
#endif
0
));
}
int mk_wcswidth(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
/*
* The following functions are the same as mk_wcwidth() and
* mk_wcswidth(), except that spacing characters in the East Asian
* Ambiguous (A) category as defined in Unicode Technical Report #11
* have a column width of 2. This variant might be useful for users of
* CJK legacy encodings who want to migrate to UCS without changing
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
int mk_wcwidth_cjk(wchar_t ucs)
{
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
return mk_wcwidth(ucs);
}
int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
+6
View File
@@ -0,0 +1,6 @@
{
"home": "https://github.com/ridiculousfish/widecharwidth",
"license": "Public domain",
"version": "Unicode 17",
"author": "ridiculousfish"
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
{
"home": "https://github.com/ibireme/yyjson",
"license": "MIT ( embed in source )",
"version": "0.10.0",
"version": "0.12.0",
"author": "ibireme"
}
+5751 -4254
View File
File diff suppressed because it is too large Load Diff
+958 -670
View File
File diff suppressed because it is too large Load Diff
+98 -32
View File
@@ -13,74 +13,137 @@
bool ffParseModuleOptions(const char* key, const char* value)
{
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
if (value && !*value) value = NULL;
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
{
FFModuleBaseInfo* baseInfo = *modules;
if (baseInfo->parseCommandOptions(baseInfo, key, value)) return true;
const char* subKey = ffOptionTestPrefix(key, baseInfo->name);
if (subKey != NULL)
{
if (subKey[0] == '\0' || subKey[0] == '-') // Key is exactly the module name or has a leading '-'
{
fprintf(stderr, "Error: unknown module key %s\n", key);
exit(477);
}
FF_STRBUF_AUTO_DESTROY moduleName = ffStrbufCreateS(baseInfo->name);
ffStrbufLowerCase(&moduleName);
FF_STRBUF_AUTO_DESTROY jsonKey = ffStrbufCreate();
bool flag = false;
for (const char* p = subKey; *p; ++p)
{
if (*p == '-')
{
if (flag)
{
fprintf(stderr, "Error: invalid double `-` in module key %s\n", key);
exit(477);
}
flag = true;
}
else
{
if (!isalpha((unsigned char)*p) && !isdigit((unsigned char)*p))
{
fprintf(stderr, "Error: invalid character `%c` in module key %s\n", *p, key);
exit(477);
}
if (flag)
{
flag = false;
ffStrbufAppendC(&jsonKey, (char) toupper((unsigned char) *p));
}
else
ffStrbufAppendC(&jsonKey, *p);
}
}
fprintf(stderr, "Error: Unsupported module option: %s\n", key);
fputs(" Support of module options has been removed. Please add the flag to the JSON config instead.\n", stderr);
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ? value : "true", value ? "\"" : "");
fputs(" See <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration> for more information.\n", stderr);
exit(477);
}
}
return false;
}
void ffPrepareCommandOption(FFdata* data)
{
FFOptionsModules* const options = &instance.config.modules;
//If we don't have a custom structure, use the default one
if(data->structure.length == 0)
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
if(ffStrbufContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME))
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME, ':'))
ffPrepareCPUUsage();
if(ffStrbufContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME))
ffPrepareDiskIO(&options->diskIo);
if(ffStrbufContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME))
ffPrepareNetIO(&options->netIo);
if(instance.config.general.multithreading)
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME, ':'))
{
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
ffPreparePublicIp(&options->publicIP);
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
ffPrepareDiskIO(&options);
}
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
ffPrepareWeather(&options->weather);
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
ffInitNetIOOptions(&options);
ffPrepareNetIO(&options);
}
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
}
}
static void genJsonConfig(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
{
yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules");
if (!modules)
modules = yyjson_mut_obj_add_arr(doc, doc->root, "modules");
yyjson_mut_val* module = yyjson_mut_obj(doc);
FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
ffStrbufLowerCase(&type);
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
if (baseInfo->generateJsonConfig)
baseInfo->generateJsonConfig(baseInfo, doc, module);
if (instance.state.fullConfig)
{
yyjson_mut_val* module = yyjson_mut_obj(doc);
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
if (yyjson_mut_obj_size(module) > 1)
yyjson_mut_arr_add_val(modules, module);
if (baseInfo->generateJsonConfig)
baseInfo->generateJsonConfig(options, doc, module);
if (yyjson_mut_obj_size(module) > 1)
yyjson_mut_arr_add_val(modules, module);
else
yyjson_mut_arr_add_strbuf(doc, modules, &type);
}
else
{
yyjson_mut_arr_add_strbuf(doc, modules, &type);
}
}
static void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
static void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
{
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
if (baseInfo->generateJsonResult)
baseInfo->generateJsonResult(baseInfo, doc, module);
baseInfo->generateJsonResult(options, doc, module);
else
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
}
static void parseStructureCommand(
const char* line,
void (*fn)(FFModuleBaseInfo *baseInfo, yyjson_mut_doc* jsonDoc),
void (*fn)(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* jsonDoc),
yyjson_mut_doc* jsonDoc
)
{
@@ -91,10 +154,13 @@ static void parseStructureCommand(
FFModuleBaseInfo* baseInfo = *modules;
if (ffStrEqualsIgnCase(line, baseInfo->name))
{
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
baseInfo->initOptions(optionBuf);
if (__builtin_expect(jsonDoc != NULL, false))
fn(baseInfo, jsonDoc);
fn(baseInfo, optionBuf, jsonDoc);
else
baseInfo->printModule(baseInfo);
baseInfo->printModule(optionBuf);
baseInfo->destroyOptions(optionBuf);
return;
}
}
@@ -134,7 +200,7 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
int len = snprintf(str, sizeof str, "%.3fms", ms);
if (thres > 0)
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ typedef struct FFdata
bool configLoaded;
} FFdata;
bool ffParseModuleOptions(const char* key, const char* value);
void ffPrepareCommandOption(FFdata* data);
void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc);
void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc);
bool ffParseModuleOptions(const char* key, const char* value);
+56 -3
View File
@@ -162,14 +162,67 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result)
return ffDBusGetUint(dbus, &subIter, result);
}
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg)
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result)
{
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
if(argType == DBUS_TYPE_INT16)
{
int16_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = value;
return true;
}
if(argType == DBUS_TYPE_INT32)
{
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
return true;
}
if(argType == DBUS_TYPE_BYTE)
{
uint8_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = value;
return true;
}
if(argType == DBUS_TYPE_UINT16)
{
uint16_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = (int16_t) value;
return true;
}
if(argType == DBUS_TYPE_UINT32)
{
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
return true;
}
if(argType != DBUS_TYPE_VARIANT)
return false;
DBusMessageIter subIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
return ffDBusGetInt(dbus, &subIter, result);
}
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2)
{
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
if(message == NULL)
return NULL;
if (arg)
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
if (arg1)
{
if (arg2)
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID);
else
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID);
}
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL);
+3 -2
View File
@@ -31,14 +31,15 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); //Returns an
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result);
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result);
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg);
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2);
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property);
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface)
{
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface);
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, NULL);
}
#endif // FF_HAVE_DBUS
+82
View File
@@ -0,0 +1,82 @@
#include "duration.h"
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result)
{
const FFOptionsDisplay* options = &instance.config.display;
bool spaceBeforeUnit = options->durationSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER;
if (totalSeconds < 60)
{
ffStrbufAppendUInt(result, totalSeconds);
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
ffStrbufAppendS(result, options->durationAbbreviation ? "sec" : "second");
if (totalSeconds != 1)
ffStrbufAppendC(result, 's');
return;
}
uint32_t seconds = (uint32_t) (totalSeconds % 60);
totalSeconds /= 60;
if (seconds >= 30)
totalSeconds++;
uint32_t minutes = (uint32_t) (totalSeconds % 60);
totalSeconds /= 60;
uint32_t hours = (uint32_t) (totalSeconds % 24);
totalSeconds /= 24;
uint32_t days = (uint32_t) totalSeconds;
if (days > 0)
{
ffStrbufAppendUInt(result, days);
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
if (options->durationAbbreviation)
{
ffStrbufAppendC(result, 'd');
if (hours > 0 || minutes > 0)
ffStrbufAppendC(result, ' ');
}
else
{
ffStrbufAppendS(result, days == 1 ? "day" : "days");
if (days >= 100)
ffStrbufAppendS(result, "(!)");
if (hours > 0 || minutes > 0)
ffStrbufAppendS(result, ", ");
}
}
if (hours > 0)
{
ffStrbufAppendUInt(result, hours);
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
if (options->durationAbbreviation)
{
ffStrbufAppendC(result, 'h');
if (minutes > 0)
ffStrbufAppendC(result, ' ');
}
else
{
ffStrbufAppendS(result, hours == 1 ? "hour" : "hours");
if (minutes > 0)
ffStrbufAppendS(result, ", ");
}
}
if (minutes > 0)
{
ffStrbufAppendUInt(result, minutes);
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
if (options->durationAbbreviation)
ffStrbufAppendC(result, 'm');
else
ffStrbufAppendS(result, minutes == 1 ? "min" : "mins");
}
}
+3
View File
@@ -0,0 +1,3 @@
#include "fastfetch.h"
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result);
+10 -9
View File
@@ -11,31 +11,31 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
switch(formatarg->type)
{
case FF_FORMAT_ARG_TYPE_INT:
ffStrbufAppendF(buffer, "%" PRIi32, *(int32_t*)formatarg->value);
ffStrbufAppendSInt(buffer, *(int32_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_UINT:
ffStrbufAppendF(buffer, "%" PRIu32, *(uint32_t*)formatarg->value);
ffStrbufAppendUInt(buffer, *(uint32_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_UINT64:
ffStrbufAppendF(buffer, "%" PRIu64, *(uint64_t*)formatarg->value);
ffStrbufAppendUInt(buffer, *(uint64_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_UINT16:
ffStrbufAppendF(buffer, "%" PRIu16, *(uint16_t*)formatarg->value);
ffStrbufAppendUInt(buffer, *(uint16_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_UINT8:
ffStrbufAppendF(buffer, "%" PRIu8, *(uint8_t*)formatarg->value);
ffStrbufAppendUInt(buffer, *(uint8_t*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_STRING:
ffStrbufAppendS(buffer, (const char*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_STRBUF:
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_FLOAT:
ffStrbufAppendF(buffer, "%f", *(float*)formatarg->value);
ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
break;
case FF_FORMAT_ARG_TYPE_DOUBLE:
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
break;
case FF_FORMAT_ARG_TYPE_BOOL:
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
@@ -107,7 +107,8 @@ static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start,
static inline bool formatArgSet(const FFformatarg* arg)
{
return arg->value != NULL && (
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) || //Also is false for NaN
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) ||
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
+25
View File
@@ -0,0 +1,25 @@
#include "frequency.h"
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result)
{
if (mhz == 0)
return false;
const FFOptionsDisplay* options = &instance.config.display;
bool spaceBeforeUnit = options->freqSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER;
int8_t ndigits = options->freqNdigits;
if (ndigits >= 0)
{
ffStrbufAppendDouble(result, mhz / 1000., ndigits, true);
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
ffStrbufAppendS(result, "GHz");
}
else
{
ffStrbufAppendUInt(result, mhz);
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
ffStrbufAppendS(result, "MHz");
}
return true;
}
+3
View File
@@ -0,0 +1,3 @@
#include "fastfetch.h"
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result);
+14 -17
View File
@@ -1,4 +1,5 @@
#include "fastfetch.h"
#include "common/init.h"
#include "common/parsing.h"
#include "common/thread.h"
#include "detection/displayserver/displayserver.h"
@@ -24,10 +25,12 @@ static void initState(FFstate* state)
state->logoHeight = 0;
state->keysHeight = 0;
state->terminalLightTheme = false;
state->titleFqdn = false;
ffPlatformInit(&state->platform);
state->configDoc = NULL;
state->resultDoc = NULL;
state->dynamicInterval = 0;
{
// don't enable bright color if the terminal is in light mode
@@ -41,14 +44,13 @@ static void defaultConfig(void)
{
ffOptionsInitLogo(&instance.config.logo);
ffOptionsInitGeneral(&instance.config.general);
ffOptionsInitModules(&instance.config.modules);
ffOptionsInitDisplay(&instance.config.display);
}
void ffInitInstance(void)
{
#ifdef WIN32
//https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendations&view=msvc-170#utf-8-support
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
setlocale(LC_ALL, ".UTF8");
#else
// Never use `setlocale(LC_ALL, "")`
@@ -73,6 +75,9 @@ static void resetConsole(void)
#if defined(_WIN32)
fflush(stdout);
#endif
if(instance.state.dynamicInterval > 0)
fputs("\033[?1049l", stdout); // Disable alternate buffer
}
#ifdef _WIN32
@@ -95,15 +100,11 @@ static void chldSignalHandler(FF_MAYBE_UNUSED int signal)
void ffStart(void)
{
#ifdef FF_START_DETECTION_THREADS
if(instance.config.general.multithreading)
startDetectionThreads();
#endif
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe && !instance.state.resultDoc;
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
#ifdef _WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
if (instance.config.display.noBuffer)
setvbuf(stdout, NULL, _IONBF, 0);
else
@@ -133,14 +134,17 @@ void ffStart(void)
if(ffDisableLinewrap)
fputs("\033[?7l", stdout);
if(instance.state.dynamicInterval > 0)
{
fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer
fflush(stdout);
}
ffLogoPrint();
}
void ffFinish(void)
{
if(instance.config.logo.printRemaining)
ffLogoPrintRemaining();
resetConsole();
}
@@ -148,7 +152,6 @@ static void destroyConfig(void)
{
ffOptionsDestroyLogo(&instance.config.logo);
ffOptionsDestroyGeneral(&instance.config.general);
ffOptionsDestroyModules(&instance.config.modules);
ffOptionsDestroyDisplay(&instance.config.display);
}
@@ -212,9 +215,6 @@ void ffListFeatures(void)
#if FF_HAVE_ZLIB
"zlib\n"
#endif
#if FF_HAVE_XFCONF
"xfconf\n"
#endif
#if FF_HAVE_SQLITE3
"sqlite3\n"
#endif
@@ -227,9 +227,6 @@ void ffListFeatures(void)
#if FF_HAVE_GLX
"glx\n"
#endif
#if FF_HAVE_OSMESA
"osmesa\n"
#endif
#if FF_HAVE_OPENCL
"opencl\n"
#endif
+7
View File
@@ -0,0 +1,7 @@
#pragma once
void ffInitInstance(void);
void ffStart(void);
void ffFinish(void);
void ffDestroyInstance(void);
void ffListFeatures(void);
+23 -22
View File
@@ -19,8 +19,7 @@
#define FF_INVALID_FD (-1)
// procfs's file can be changed between read calls such as /proc/meminfo and /proc/uptime.
// one safe way to read correct data is reading the whole file in a single read syscall
// 8192 comes from procps-ng: https://gitlab.com/procps-ng/procps/-/blob/master/library/meminfo.c?ref_type=heads#L39
#define PROC_FILE_BUFFSIZ 8192
#define PROC_FILE_BUFFSIZ (32 * 1024)
#endif
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
@@ -32,6 +31,7 @@ static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
#endif
}
FF_C_NONNULL(3)
static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* data)
{
#ifndef _WIN32
@@ -42,18 +42,22 @@ static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* dat
#endif
}
FF_C_NONNULL(2)
static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content)
{
return ffWriteFDData(fd, content->length, content->chars);
}
FF_C_NONNULL(1, 3)
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data);
FF_C_NONNULL(1, 2)
static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer)
{
return ffWriteFileData(fileName, buffer->length, buffer->chars);
}
FF_C_NONNULL(3)
static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
{
#ifndef _WIN32
@@ -67,26 +71,32 @@ static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
#endif
}
FF_C_NONNULL(1, 3)
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data);
FF_C_NONNULL(2, 4)
ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data);
FF_C_NONNULL(2)
bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
FF_C_NONNULL(1, 2)
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer);
FF_C_NONNULL(2, 3)
bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer);
FF_C_NONNULL(1, 2)
static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer)
{
ffStrbufClear(buffer);
return ffAppendFileBuffer(fileName, buffer);
}
FF_C_NONNULL(2, 3)
static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer)
{
ffStrbufClear(buffer);
return ffAppendFileBufferRelative(dfd, fileName, buffer);
}
//Bit flags, combine with |
typedef enum __attribute__((__packed__)) FFPathType
{
FF_PATHTYPE_FILE = 1 << 0,
@@ -95,6 +105,7 @@ typedef enum __attribute__((__packed__)) FFPathType
FF_PATHTYPE_FORCE_UNSIGNED = UINT8_MAX,
} FFPathType;
FF_C_NONNULL(1)
static inline bool ffPathExists(const char* path, FFPathType pathType)
{
#ifdef _WIN32
@@ -119,7 +130,6 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
}
else
{
#if (__APPLE__ || __HAIKU__) // #1395
struct stat fileStat;
if(stat(path, &fileStat) != 0)
return false;
@@ -131,24 +141,6 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
if(pathType & FF_PATHTYPE_DIRECTORY && mode == S_IFDIR)
return true;
#else
size_t len = strlen(path);
assert(len < PATH_MAX);
if (len == 0) return false;
int ret;
if (path[len - 1] != '/')
{
char buf[PATH_MAX + 1];
memcpy(buf, path, len);
buf[len] = '/';
buf[len + 1] = 0;
ret = access(buf, F_OK);
}
else
ret = access(path, F_OK);
return pathType == FF_PATHTYPE_DIRECTORY ? ret == 0 : ret == -1 && errno == ENOTDIR;
#endif
}
#endif
@@ -156,11 +148,13 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
return false;
}
FF_C_NONNULL(1, 2)
bool ffPathExpandEnv(const char* in, FFstrbuf* out);
#define FF_IO_TERM_RESP_WAIT_MS 100 // #554
FF_C_SCANF(3, 4)
FF_C_NONNULL(1, 3)
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...);
// Not thread safe!
@@ -177,6 +171,7 @@ static inline void ffUnsuppressIO(bool* suppressed)
void ffListFilesRecursively(const char* path, bool pretty);
FF_C_NONNULL(1)
static inline bool wrapClose(FFNativeFD* pfd)
{
assert(pfd);
@@ -196,6 +191,7 @@ static inline bool wrapClose(FFNativeFD* pfd)
}
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
FF_C_NONNULL(1)
static inline bool wrapFclose(FILE** pfile)
{
assert(pfile);
@@ -206,6 +202,7 @@ static inline bool wrapFclose(FILE** pfile)
}
#define FF_AUTO_CLOSE_FILE __attribute__((__cleanup__(wrapFclose)))
FF_C_NONNULL(1)
#ifndef _WIN32
static inline bool wrapClosedir(DIR** pdir)
{
@@ -227,6 +224,7 @@ static inline bool wrapClosedir(HANDLE* pdir)
#endif
#define FF_AUTO_CLOSE_DIR __attribute__((__cleanup__(wrapClosedir)))
FF_C_NONNULL(1, 2, 3)
static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result)
{
// configDirs is a list of FFstrbufs include the trailing slash
@@ -242,6 +240,9 @@ static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char*
return false;
}
FFNativeFD ffGetNullFD(void);
bool ffRemoveFile(const char* fileName);
#ifdef _WIN32
// Only O_RDONLY is supported
HANDLE openat(HANDLE dfd, const char* fileName, bool directory);
+35 -12
View File
@@ -15,11 +15,8 @@
#if FF_HAVE_WORDEXP
#include <wordexp.h>
#elif FF_HAVE_GLOB
#warning "<wordexp.h> is not available, use <glob.h> instead"
#include <glob.h>
#else
#warning "Neither <wordexp.h> nor <glob.h> is available"
#include <glob.h>
#endif
static void createSubfolders(const char* fileName)
@@ -136,14 +133,14 @@ bool ffAppendFileBufferRelative(int dfd, const char* fileName, FFstrbuf* buffer)
return ffAppendFDBuffer(fd, buffer);
}
bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* out)
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
{
bool result = false;
#if FF_HAVE_WORDEXP // https://github.com/termux/termux-packages/pull/7056
#if FF_HAVE_WORDEXP
wordexp_t exp;
if (wordexp(in, &exp, 0) != 0)
if (wordexp(in, &exp, 0) != 0) // WARN: 0 = no safety flags; command substitution allowed
return false;
if (exp.we_wordc >= 1)
@@ -154,16 +151,23 @@ bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* o
wordfree(&exp);
#elif FF_HAVE_GLOB
#else
glob_t gb;
if (glob(in, GLOB_NOSORT | GLOB_TILDE, NULL, &gb) != 0)
if (glob(in, GLOB_NOSORT
#ifdef GLOB_TILDE
| GLOB_TILDE
#endif
#ifdef GLOB_BRACE
| GLOB_BRACE
#endif
, NULL, &gb) != 0)
return false;
if (gb.gl_matchc >= 1)
if (gb.gl_pathc >= 1)
{
result = true;
ffStrbufSetS(out, gb.gl_pathv[gb.gl_matchc > 1 ? ffTimeGetNow() % gb.gl_matchc : 0]);
ffStrbufSetS(out, gb.gl_pathv[gb.gl_pathc > 1 ? ffTimeGetNow() % (unsigned) gb.gl_pathc : 0]);
}
globfree(&gb);
@@ -256,6 +260,11 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
bool ffSuppressIO(bool suppress)
{
#ifndef NDEBUG
if (instance.config.display.debugMode)
return false;
#endif
static bool init = false;
static int origOut = -1;
static int origErr = -1;
@@ -285,7 +294,7 @@ bool ffSuppressIO(bool suppress)
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty)
{
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY);
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC);
if (dfd < 0)
return;
@@ -353,3 +362,17 @@ void ffListFilesRecursively(const char* path, bool pretty)
ffStrbufEnsureEndsWithC(&folder, '/');
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
}
FFNativeFD ffGetNullFD(void)
{
static FFNativeFD hNullFile = -1;
if (hNullFile != -1)
return hNullFile;
hNullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
return hNullFile;
}
bool ffRemoveFile(const char* fileName)
{
return unlink(fileName) == 0;
}
+39 -2
View File
@@ -147,6 +147,14 @@ ssize_t ffReadFileDataRelative(HANDLE dfd, const char* fileName, size_t dataSize
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
{
if (in[0] == '~') {
if ((in[1] == '/' || in[1] == '\\' || in[1] == '\0') && !ffStrContainsC(in, '%')) {
ffStrbufSet(out, &instance.state.platform.homeDir);
ffStrbufAppendS(out, in + 1);
return true;
}
}
DWORD length = ExpandEnvironmentStringsA(in, NULL, 0);
if (length <= 1) return false;
@@ -159,10 +167,15 @@ bool ffPathExpandEnv(const char* in, FFstrbuf* out)
bool ffSuppressIO(bool suppress)
{
#ifndef NDEBUG
if (instance.config.display.debugMode)
return false;
#endif
static bool init = false;
static HANDLE hOrigOut = INVALID_HANDLE_VALUE;
static HANDLE hOrigErr = INVALID_HANDLE_VALUE;
static HANDLE hNullFile = INVALID_HANDLE_VALUE;
HANDLE hNullFile = ffGetNullFD();
static int fOrigOut = -1;
static int fOrigErr = -1;
static int fNullFile = -1;
@@ -174,7 +187,6 @@ bool ffSuppressIO(bool suppress)
hOrigOut = GetStdHandle(STD_OUTPUT_HANDLE);
hOrigErr = GetStdHandle(STD_ERROR_HANDLE);
hNullFile = CreateFileW(L"NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
fOrigOut = _dup(STDOUT_FILENO);
fOrigErr = _dup(STDERR_FILENO);
fNullFile = _open_osfhandle((intptr_t) hNullFile, 0);
@@ -339,3 +351,28 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
return NULL;
}
FFNativeFD ffGetNullFD(void)
{
static FFNativeFD hNullFile = INVALID_HANDLE_VALUE;
if (hNullFile != INVALID_HANDLE_VALUE)
return hNullFile;
hNullFile = CreateFileW(
L"NUL",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
0,
&(SECURITY_ATTRIBUTES){
.nLength = sizeof(SECURITY_ATTRIBUTES),
.lpSecurityDescriptor = NULL,
.bInheritHandle = TRUE,
});
return hNullFile;
}
bool ffRemoveFile(const char* fileName)
{
return DeleteFileA(fileName) != FALSE;
}
+136 -43
View File
@@ -4,6 +4,7 @@
#include "common/printing.h"
#include "common/io/io.h"
#include "common/time.h"
#include "detection/version/version.h"
#include "modules/modules.h"
#include "util/stringUtils.h"
@@ -11,52 +12,57 @@
#include <ctype.h>
#include <inttypes.h>
bool ffJsonConfigParseModuleArgs(const char* key, yyjson_val* val, FFModuleArgs* moduleArgs)
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs)
{
if(ffStrEqualsIgnCase(key, "key"))
if (unsafe_yyjson_equals_str(key, "type") || unsafe_yyjson_equals_str(key, "condition"))
return true;
if (unsafe_yyjson_equals_str(key, "key"))
{
ffStrbufSetNS(&moduleArgs->key, (uint32_t) yyjson_get_len(val), yyjson_get_str(val));
ffStrbufSetJsonVal(&moduleArgs->key, val);
return true;
}
else if(ffStrEqualsIgnCase(key, "format"))
else if (unsafe_yyjson_equals_str(key, "format"))
{
ffStrbufSetNS(&moduleArgs->outputFormat, (uint32_t) yyjson_get_len(val), yyjson_get_str(val));
ffStrbufSetJsonVal(&moduleArgs->outputFormat, val);
return true;
}
else if(ffStrEqualsIgnCase(key, "outputColor"))
else if (unsafe_yyjson_equals_str(key, "outputColor"))
{
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->outputColor);
return true;
}
else if(ffStrEqualsIgnCase(key, "keyColor"))
else if (unsafe_yyjson_equals_str(key, "keyColor"))
{
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->keyColor);
return true;
}
else if(ffStrEqualsIgnCase(key, "keyWidth"))
else if (unsafe_yyjson_equals_str(key, "keyWidth"))
{
moduleArgs->keyWidth = (uint32_t) yyjson_get_uint(val);
return true;
}
else if(ffStrEqualsIgnCase(key, "keyIcon"))
else if (unsafe_yyjson_equals_str(key, "keyIcon"))
{
ffStrbufSetS(&moduleArgs->keyIcon, yyjson_get_str(val));
ffStrbufSetJsonVal(&moduleArgs->keyIcon, val);
return true;
}
return false;
}
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* defaultModuleArgs, FFModuleArgs* moduleArgs)
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs)
{
if (!ffStrbufEqual(&defaultModuleArgs->key, &moduleArgs->key))
if (moduleArgs->key.length > 0)
yyjson_mut_obj_add_strbuf(doc, module, "key", &moduleArgs->key);
if (!ffStrbufEqual(&defaultModuleArgs->outputFormat, &moduleArgs->outputFormat))
if (moduleArgs->outputFormat.length > 0)
yyjson_mut_obj_add_strbuf(doc, module, "format", &moduleArgs->outputFormat);
if (!ffStrbufEqual(&defaultModuleArgs->keyColor, &moduleArgs->keyColor))
if (moduleArgs->outputColor.length > 0)
yyjson_mut_obj_add_strbuf(doc, module, "outputColor", &moduleArgs->outputColor);
if (moduleArgs->keyColor.length > 0)
yyjson_mut_obj_add_strbuf(doc, module, "keyColor", &moduleArgs->keyColor);
if (moduleArgs->keyWidth != defaultModuleArgs->keyWidth)
if (moduleArgs->keyWidth > 0)
yyjson_mut_obj_add_uint(doc, module, "keyWidth", moduleArgs->keyWidth);
if (!ffStrbufEqual(&defaultModuleArgs->keyIcon, &moduleArgs->keyIcon))
if (moduleArgs->keyIcon.length > 0)
yyjson_mut_obj_add_strbuf(doc, module, "keyIcon", &moduleArgs->keyIcon);
}
@@ -95,16 +101,6 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p
return "Invalid enum value type; must be a string or integer";
}
static inline void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
{
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
if (baseInfo->generateJsonResult)
baseInfo->generateJsonResult(baseInfo, doc, module);
else
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
}
static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_mut_doc* jsonDoc)
{
if(!ffCharIsEnglishAlphabet(type[0])) return false;
@@ -114,20 +110,47 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
FFModuleBaseInfo* baseInfo = *modules;
if (ffStrEqualsIgnCase(type, baseInfo->name))
{
if (jsonVal) baseInfo->parseJsonObject(baseInfo, jsonVal);
if (__builtin_expect(jsonDoc != NULL, false))
genJsonResult(baseInfo, jsonDoc);
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
baseInfo->initOptions(optionBuf);
if (jsonVal) baseInfo->parseJsonObject(optionBuf, jsonVal);
bool succeeded;
if (jsonDoc)
{
yyjson_mut_val* module = yyjson_mut_arr_add_obj(jsonDoc, jsonDoc->root);
yyjson_mut_obj_add_str(jsonDoc, module, "type", baseInfo->name);
if (baseInfo->generateJsonResult)
succeeded = baseInfo->generateJsonResult(optionBuf, jsonDoc, module);
else
{
yyjson_mut_obj_add_str(jsonDoc, module, "error", "Unsupported for JSON format");
succeeded = false;
}
}
else
baseInfo->printModule(baseInfo);
return true;
succeeded = baseInfo->printModule(optionBuf);
baseInfo->destroyOptions(optionBuf);
return succeeded;
}
}
if (jsonDoc)
{
yyjson_mut_val* module = yyjson_mut_arr_add_obj(jsonDoc, jsonDoc->root);
yyjson_mut_obj_add_strcpy(jsonDoc, module, "type", type);
yyjson_mut_obj_add_str(jsonDoc, module, "error", "Unknown module type");
}
else
{
FFModuleArgs moduleArgs;
ffOptionInitModuleArg(&moduleArgs, "");
ffPrintError(type, 0, &moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown module type");
ffOptionDestroyModuleArg(&moduleArgs);
}
return false;
}
static void prepareModuleJsonObject(const char* type, yyjson_val* module)
{
FFconfig* cfg = &instance.config;
switch (type[0])
{
case 'b': case 'B': {
@@ -135,41 +158,78 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
ffPrepareCPUUsage();
break;
}
case 'c': case 'C': {
if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME))
{
__attribute__((__cleanup__(ffDestroyCommandOptions))) FFCommandOptions options;
ffInitCommandOptions(&options);
if (module) ffCommandModuleInfo.parseJsonObject(&options, module);
ffPrepareCommand(&options);
}
break;
}
case 'd': case 'D': {
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME))
{
if (module) cfg->modules.diskIo.moduleInfo.parseJsonObject(&cfg->modules.diskIo, module);
ffPrepareDiskIO(&cfg->modules.diskIo);
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
if (module) ffDiskIOModuleInfo.parseJsonObject(&options, module);
ffPrepareDiskIO(&options);
}
break;
}
case 'n': case 'N': {
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME))
{
if (module) cfg->modules.netIo.moduleInfo.parseJsonObject(&cfg->modules.netIo, module);
ffPrepareNetIO(&cfg->modules.netIo);
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
ffInitNetIOOptions(&options);
if (module) ffNetIOModuleInfo.parseJsonObject(&options, module);
ffPrepareNetIO(&options);
}
break;
}
case 'p': case 'P': {
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME))
{
if (module) cfg->modules.publicIP.moduleInfo.parseJsonObject(&cfg->modules.publicIP, module);
ffPreparePublicIp(&cfg->modules.publicIP);
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
if (module) ffPublicIPModuleInfo.parseJsonObject(&options, module);
ffPreparePublicIp(&options);
}
break;
}
case 'w': case 'W': {
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME))
{
if (module) cfg->modules.weather.moduleInfo.parseJsonObject(&cfg->modules.weather, module);
ffPrepareWeather(&cfg->modules.weather);
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
if (module) ffWeatherModuleInfo.parseJsonObject(&options, module);
ffPrepareWeather(&options);
}
break;
}
}
}
static bool matchesJsonArray(const char* str, yyjson_val* val)
{
assert(val);
if (unsafe_yyjson_is_str(val))
return ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(val));
if (!unsafe_yyjson_is_arr(val)) return false;
size_t idx, max;
yyjson_val* item;
yyjson_arr_foreach(val, idx, max, item)
{
if (yyjson_is_str(item) && ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(item)))
return true;
}
return false;
}
static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
{
yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc);
@@ -182,6 +242,7 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
if (!modules) return NULL;
if (!yyjson_is_arr(modules)) return "Property 'modules' must be an array of strings or objects";
bool succeeded = true;
int32_t thres = instance.config.display.stat;
yyjson_val* item;
size_t idx, max;
@@ -197,6 +258,38 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
module = NULL;
else if (yyjson_is_obj(module))
{
yyjson_val* conditions = yyjson_obj_get(module, "condition");
if (conditions)
{
if (!yyjson_is_obj(conditions))
return "Property 'conditions' must be an object";
yyjson_val* system = yyjson_obj_get(conditions, "system");
if (system && !matchesJsonArray(ffVersionResult.sysName, system))
continue;
system = yyjson_obj_get(conditions, "!system");
if (system && matchesJsonArray(ffVersionResult.sysName, system))
continue;
yyjson_val* arch = yyjson_obj_get(conditions, "arch");
if (arch && !matchesJsonArray(ffVersionResult.architecture, arch))
continue;
arch = yyjson_obj_get(conditions, "!arch");
if (arch && matchesJsonArray(ffVersionResult.architecture, arch))
continue;
yyjson_val* previousSucceeded = yyjson_obj_get(conditions, "succeeded");
if (previousSucceeded && !unsafe_yyjson_is_null(previousSucceeded))
{
if (!unsafe_yyjson_is_bool(previousSucceeded))
return "Property 'succeeded' in 'condition' must be a boolean";
if (succeeded != unsafe_yyjson_get_bool(previousSucceeded))
continue;
}
}
type = yyjson_get_str(yyjson_obj_get(module, "type"));
if (!type) return "module object must contain a \"type\" key ( case sensitive )";
if (yyjson_obj_size(module) == 1) // contains only Property type
@@ -207,8 +300,8 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
if(prepare)
prepareModuleJsonObject(type, module);
else if(!parseModuleJsonObject(type, module, jsonDoc))
return "Unknown module type";
else
succeeded = parseModuleJsonObject(type, module, jsonDoc);
if(!prepare && thres >= 0)
{
@@ -224,7 +317,7 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
int len = snprintf(str, sizeof str, "%.3fms", ms);
if (thres > 0)
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
}
}
+2 -2
View File
@@ -2,10 +2,10 @@
#include "fastfetch.h"
bool ffJsonConfigParseModuleArgs(const char* key, yyjson_val* val, FFModuleArgs* moduleArgs);
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs);
const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[]);
void ffPrintJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc);
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* defaultModuleArgs, FFModuleArgs* moduleArgs);
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs);
yyjson_api_inline yyjson_mut_val* yyjson_mut_strbuf(yyjson_mut_doc *doc, const FFstrbuf* buf) {
return yyjson_mut_strncpy(doc, buf->chars, buf->length);
+1 -1
View File
@@ -52,7 +52,7 @@ static void* libraryLoad(const char* path, int maxVersion)
for(int i = maxVersion; i >= 0; --i)
{
uint32_t originalLength = pathbuf.length;
ffStrbufAppendF(&pathbuf, "%i", i);
ffStrbufAppendSInt(&pathbuf, i);
result = dlopen(pathbuf.chars, FF_DLOPEN_FLAGS);
if(result != NULL)
+1 -1
View File
@@ -74,7 +74,7 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...);
FF_MAYBE_UNUSED void* libraryObjectName = NULL; // Placeholder
#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
symbolMapping = (__typeof__(&symbolName)) &symbolName
symbolMapping = (__typeof__(&symbolName)) &symbolName;
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
FF_MAYBE_UNUSED __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
+74 -74
View File
@@ -1,69 +1,69 @@
#include "fastfetch.h"
#include "modules/modules.h"
static FFModuleBaseInfo* A[] = {
NULL,
};
static FFModuleBaseInfo* B[] = {
(FFModuleBaseInfo*) &instance.config.modules.battery,
(FFModuleBaseInfo*) &instance.config.modules.bios,
(FFModuleBaseInfo*) &instance.config.modules.bluetooth,
(FFModuleBaseInfo*) &instance.config.modules.bluetoothRadio,
(FFModuleBaseInfo*) &instance.config.modules.board,
(FFModuleBaseInfo*) &instance.config.modules.bootmgr,
(FFModuleBaseInfo*) &instance.config.modules.break_,
(FFModuleBaseInfo*) &instance.config.modules.brightness,
(FFModuleBaseInfo*) &instance.config.modules.btrfs,
&ffBatteryModuleInfo,
&ffBiosModuleInfo,
&ffBluetoothModuleInfo,
&ffBluetoothRadioModuleInfo,
&ffBoardModuleInfo,
&ffBootmgrModuleInfo,
&ffBreakModuleInfo,
&ffBrightnessModuleInfo,
&ffBtrfsModuleInfo,
NULL,
};
static FFModuleBaseInfo* C[] = {
(FFModuleBaseInfo*) &instance.config.modules.camera,
(FFModuleBaseInfo*) &instance.config.modules.chassis,
(FFModuleBaseInfo*) &instance.config.modules.command,
(FFModuleBaseInfo*) &instance.config.modules.colors,
(FFModuleBaseInfo*) &instance.config.modules.cpu,
(FFModuleBaseInfo*) &instance.config.modules.cpuCache,
(FFModuleBaseInfo*) &instance.config.modules.cpuUsage,
(FFModuleBaseInfo*) &instance.config.modules.cursor,
(FFModuleBaseInfo*) &instance.config.modules.custom,
&ffCameraModuleInfo,
&ffChassisModuleInfo,
&ffCommandModuleInfo,
&ffColorsModuleInfo,
&ffCPUModuleInfo,
&ffCPUCacheModuleInfo,
&ffCPUUsageModuleInfo,
&ffCursorModuleInfo,
&ffCustomModuleInfo,
NULL,
};
static FFModuleBaseInfo* D[] = {
(FFModuleBaseInfo*) &instance.config.modules.dateTime,
(FFModuleBaseInfo*) &instance.config.modules.de,
(FFModuleBaseInfo*) &instance.config.modules.display,
(FFModuleBaseInfo*) &instance.config.modules.disk,
(FFModuleBaseInfo*) &instance.config.modules.diskIo,
(FFModuleBaseInfo*) &instance.config.modules.dns,
&ffDateTimeModuleInfo,
&ffDEModuleInfo,
&ffDisplayModuleInfo,
&ffDiskModuleInfo,
&ffDiskIOModuleInfo,
&ffDNSModuleInfo,
NULL,
};
static FFModuleBaseInfo* E[] = {
(FFModuleBaseInfo*) &instance.config.modules.editor,
&ffEditorModuleInfo,
NULL,
};
static FFModuleBaseInfo* F[] = {
(FFModuleBaseInfo*) &instance.config.modules.font,
&ffFontModuleInfo,
NULL,
};
static FFModuleBaseInfo* G[] = {
(FFModuleBaseInfo*) &instance.config.modules.gamepad,
(FFModuleBaseInfo*) &instance.config.modules.gpu,
&ffGamepadModuleInfo,
&ffGPUModuleInfo,
NULL,
};
static FFModuleBaseInfo* H[] = {
(FFModuleBaseInfo*) &instance.config.modules.host,
&ffHostModuleInfo,
NULL,
};
static FFModuleBaseInfo* I[] = {
(FFModuleBaseInfo*) &instance.config.modules.icons,
(FFModuleBaseInfo*) &instance.config.modules.initSystem,
&ffIconsModuleInfo,
&ffInitSystemModuleInfo,
NULL,
};
@@ -72,47 +72,47 @@ static FFModuleBaseInfo* J[] = {
};
static FFModuleBaseInfo* K[] = {
(FFModuleBaseInfo*) &instance.config.modules.kernel,
(FFModuleBaseInfo*) &instance.config.modules.keyboard,
&ffKernelModuleInfo,
&ffKeyboardModuleInfo,
NULL,
};
static FFModuleBaseInfo* L[] = {
(FFModuleBaseInfo*) &instance.config.modules.lm,
(FFModuleBaseInfo*) &instance.config.modules.loadavg,
(FFModuleBaseInfo*) &instance.config.modules.locale,
(FFModuleBaseInfo*) &instance.config.modules.localIP,
&ffLMModuleInfo,
&ffLoadavgModuleInfo,
&ffLocaleModuleInfo,
&ffLocalIPModuleInfo,
NULL,
};
static FFModuleBaseInfo* M[] = {
(FFModuleBaseInfo*) &instance.config.modules.media,
(FFModuleBaseInfo*) &instance.config.modules.memory,
(FFModuleBaseInfo*) &instance.config.modules.monitor,
(FFModuleBaseInfo*) &instance.config.modules.mouse,
&ffMediaModuleInfo,
&ffMemoryModuleInfo,
&ffMonitorModuleInfo,
&ffMouseModuleInfo,
NULL,
};
static FFModuleBaseInfo* N[] = {
(FFModuleBaseInfo*) &instance.config.modules.netIo,
&ffNetIOModuleInfo,
NULL,
};
static FFModuleBaseInfo* O[] = {
(FFModuleBaseInfo*) &instance.config.modules.openCL,
(FFModuleBaseInfo*) &instance.config.modules.openGL,
(FFModuleBaseInfo*) &instance.config.modules.os,
&ffOpenCLModuleInfo,
&ffOpenGLModuleInfo,
&ffOSModuleInfo,
NULL,
};
static FFModuleBaseInfo* P[] = {
(FFModuleBaseInfo*) &instance.config.modules.packages,
(FFModuleBaseInfo*) &instance.config.modules.physicalDisk,
(FFModuleBaseInfo*) &instance.config.modules.physicalMemory,
(FFModuleBaseInfo*) &instance.config.modules.player,
(FFModuleBaseInfo*) &instance.config.modules.powerAdapter,
(FFModuleBaseInfo*) &instance.config.modules.processes,
(FFModuleBaseInfo*) &instance.config.modules.publicIP,
&ffPackagesModuleInfo,
&ffPhysicalDiskModuleInfo,
&ffPhysicalMemoryModuleInfo,
&ffPlayerModuleInfo,
&ffPowerAdapterModuleInfo,
&ffProcessesModuleInfo,
&ffPublicIPModuleInfo,
NULL,
};
@@ -125,42 +125,42 @@ static FFModuleBaseInfo* R[] = {
};
static FFModuleBaseInfo* S[] = {
(FFModuleBaseInfo*) &instance.config.modules.separator,
(FFModuleBaseInfo*) &instance.config.modules.shell,
(FFModuleBaseInfo*) &instance.config.modules.sound,
(FFModuleBaseInfo*) &instance.config.modules.swap,
&ffSeparatorModuleInfo,
&ffShellModuleInfo,
&ffSoundModuleInfo,
&ffSwapModuleInfo,
NULL,
};
static FFModuleBaseInfo* T[] = {
(FFModuleBaseInfo*) &instance.config.modules.terminal,
(FFModuleBaseInfo*) &instance.config.modules.terminalFont,
(FFModuleBaseInfo*) &instance.config.modules.terminalSize,
(FFModuleBaseInfo*) &instance.config.modules.terminalTheme,
(FFModuleBaseInfo*) &instance.config.modules.title,
(FFModuleBaseInfo*) &instance.config.modules.theme,
(FFModuleBaseInfo*) &instance.config.modules.tpm,
&ffTerminalModuleInfo,
&ffTerminalFontModuleInfo,
&ffTerminalSizeModuleInfo,
&ffTerminalThemeModuleInfo,
&ffTitleModuleInfo,
&ffThemeModuleInfo,
&ffTPMModuleInfo,
NULL,
};
static FFModuleBaseInfo* U[] = {
(FFModuleBaseInfo*) &instance.config.modules.uptime,
(FFModuleBaseInfo*) &instance.config.modules.users,
&ffUptimeModuleInfo,
&ffUsersModuleInfo,
NULL,
};
static FFModuleBaseInfo* V[] = {
(FFModuleBaseInfo*) &instance.config.modules.version,
(FFModuleBaseInfo*) &instance.config.modules.vulkan,
&ffVersionModuleInfo,
&ffVulkanModuleInfo,
NULL,
};
static FFModuleBaseInfo* W[] = {
(FFModuleBaseInfo*) &instance.config.modules.wallpaper,
(FFModuleBaseInfo*) &instance.config.modules.weather,
(FFModuleBaseInfo*) &instance.config.modules.wm,
(FFModuleBaseInfo*) &instance.config.modules.wifi,
(FFModuleBaseInfo*) &instance.config.modules.wmTheme,
&ffWallpaperModuleInfo,
&ffWeatherModuleInfo,
&ffWMModuleInfo,
&ffWifiModuleInfo,
&ffWMThemeModuleInfo,
NULL,
};
@@ -173,7 +173,7 @@ static FFModuleBaseInfo* Y[] = {
};
static FFModuleBaseInfo* Z[] = {
(FFModuleBaseInfo*) &instance.config.modules.zpool,
&ffZpoolModuleInfo,
NULL,
};
+13 -19
View File
@@ -2,29 +2,23 @@
#ifndef _WIN32
#include <net/if.h>
#else
#define IF_NAMESIZE 16
#include <netinet/in.h>
#endif
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex);
enum { IF_INDEX_UNINITIALIZED = (uint32_t) -1, IF_INDEX_INVALID = (uint32_t) -2 };
static uint32_t ifIndex = IF_INDEX_UNINITIALIZED;
static char ifName[IF_NAMESIZE + 1];
static inline void init()
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void)
{
if (ifIndex == (uint32_t) IF_INDEX_UNINITIALIZED && !ffNetifGetDefaultRouteImpl(ifName, &ifIndex))
ifIndex = (uint32_t) IF_INDEX_INVALID;
static FFNetifDefaultRouteResult result;
if (result.status == FF_NETIF_UNINITIALIZED) {
result.status = ffNetifGetDefaultRouteImplV4(&result) ? FF_NETIF_OK : FF_NETIF_INVALID;
}
return &result;
}
const char* ffNetifGetDefaultRouteIfName()
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void)
{
init();
return ifName;
}
uint32_t ffNetifGetDefaultRouteIfIndex()
{
init();
return ifIndex;
static FFNetifDefaultRouteResult result;
if (result.status == FF_NETIF_UNINITIALIZED) {
result.status = ffNetifGetDefaultRouteImplV6(&result) ? FF_NETIF_OK : FF_NETIF_INVALID;
}
return &result;
}
+23 -2
View File
@@ -3,7 +3,28 @@
#include "fastfetch.h"
#ifndef _WIN32
const char* ffNetifGetDefaultRouteIfName();
#include <net/if.h>
#include <netinet/in.h>
#endif
uint32_t ffNetifGetDefaultRouteIfIndex();
typedef enum __attribute__((__packed__)) FFNetifDefaultRouteResultStatus {
FF_NETIF_UNINITIALIZED,
FF_NETIF_INVALID,
FF_NETIF_OK
} FFNetifDefaultRouteResultStatus;
typedef struct FFNetifDefaultRouteResult {
uint32_t ifIndex;
#ifndef _WIN32
char ifName[IF_NAMESIZE + 1];
uint32_t preferredSourceAddrV4;
#endif
enum FFNetifDefaultRouteResultStatus status;
} FFNetifDefaultRouteResult;
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result);
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result);
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void);
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void);
+201
View File
@@ -0,0 +1,201 @@
#include "netif.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
#if __APPLE__
// https://github.com/apple-oss-distributions/network_cmds/blob/8f38231438e6a4d16ef8015e97e12c2c05105644/rtsol.tproj/if.c#L243
#define ROUNDUP(a) ROUNDUP2((a), sizeof(uint32_t))
#elif __sun
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L339
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
#else
#error unknown platform
#endif
static struct sockaddr *
get_rt_address(struct rt_msghdr *rtm, int desired)
{
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
for (int i = 0; i < RTAX_MAX; i++)
{
if (rtm->rtm_addrs & (1 << i))
{
if ((1 << i) == desired)
return sa;
#ifndef __sun
uint32_t salen = sa->sa_len;
#else
uint32_t salen;
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L2941
switch (sa->sa_family) {
case AF_INET:
salen = sizeof (struct sockaddr_in);
break;
case AF_LINK:
salen = sizeof (struct sockaddr_dl);
break;
case AF_INET6:
salen = sizeof (struct sockaddr_in6);
break;
default:
salen = sizeof (struct sockaddr);
break;
}
#endif
sa = (struct sockaddr *)(ROUNDUP(salen) + (char *)sa);
}
}
return NULL;
}
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
{
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET);
if (pfRoute < 0)
return false;
{
struct timeval timeout = {1, 0};
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
}
int pid = getpid();
struct {
struct rt_msghdr hdr;
struct sockaddr_in dst;
uint8_t data[512];
} rtmsg = {
.hdr = {
.rtm_type = RTM_GET,
.rtm_flags = RTF_UP | RTF_GATEWAY,
.rtm_version = RTM_VERSION,
.rtm_addrs = RTA_DST | RTA_IFP | RTA_IFA,
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
.rtm_pid = pid,
.rtm_seq = 1,
},
.dst = {
.sin_family = AF_INET,
#ifndef __sun
.sin_len = sizeof(rtmsg.dst),
#endif
},
};
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
return false;
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid))
;
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
#endif
{
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
if (sdl
#ifndef __sun
&& sdl->sdl_len
#endif
)
{
assert(sdl->sdl_nlen <= IF_NAMESIZE);
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
result->ifName[sdl->sdl_nlen] = '\0';
result->ifIndex = sdl->sdl_index;
// Get the preferred source address
struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(&rtmsg.hdr, RTA_IFA);
if (src && src->sin_family == AF_INET)
result->preferredSourceAddrV4 = src->sin_addr.s_addr;
return true;
}
return false;
}
return false;
}
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
{
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
if (pfRoute < 0)
return false;
{
struct timeval timeout = {1, 0};
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
}
int pid = getpid();
struct {
struct rt_msghdr hdr;
struct sockaddr_in6 dst;
uint8_t data[512];
} rtmsg = {
.hdr = {
.rtm_type = RTM_GET,
.rtm_flags = RTF_UP | RTF_GATEWAY,
.rtm_version = RTM_VERSION,
.rtm_addrs = RTA_DST | RTA_IFP,
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
.rtm_pid = pid,
.rtm_seq = 2,
},
.dst = {
.sin6_family = AF_INET6,
#ifndef __sun
.sin6_len = sizeof(rtmsg.dst),
#endif
},
};
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
return false;
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == pid))
;
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
#endif
{
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
if (sdl
#ifndef __sun
&& sdl->sdl_len
#endif
)
{
assert(sdl->sdl_nlen <= IF_NAMESIZE);
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
result->ifName[sdl->sdl_nlen] = '\0';
result->ifIndex = sdl->sdl_index;
return true;
}
return false;
}
return false;
}
+77 -61
View File
@@ -1,27 +1,31 @@
#include "netif.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
#if defined(__APPLE__)
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
#elif defined(__NetBSD__)
# define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
#elif defined(__FreeBSD__)
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
#elif defined(__OpenBSD__)
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
#elif defined(__sun)
# define ROUNDUP(a) ROUNDUP2((a), _SS_ALIGNSIZE)
#if __DragonFly__
// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/cf0aa2f1e47a3f0a6055fe427563cb3f3e627064/sys/net/route.h#L315C9-L315C19
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
#elif __FreeBSD__
// https://github.com/freebsd/freebsd-src/blob/e4c0ecba44b20ebb2e4d80978c2cb6d16b730cb9/sys/net/route.h#L368C9-L368C16
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
#elif __NetBSD__
// https://github.com/NetBSD/src/blob/29beb637d057520c0ed37ac2cde966f7cc0cadf4/sys/net/route.h#L330
#define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
#elif __OpenBSD__
// https://github.com/openbsd/src/blob/ca647cfa4ec3ccb8360714bc0ebc32a394f7fb6a/regress/sys/netinet/bindconnect/bindconnect.c#L250
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
#else
# error unknown platform
#error unknown platform
#endif
static struct sockaddr *
@@ -35,76 +39,88 @@ get_rt_address(struct rt_msghdr *rtm, int desired)
{
if ((1 << i) == desired)
return sa;
#ifdef __sun
sa = (struct sockaddr *)(ROUNDUP(sizeof(struct sockaddr)) + (char *)sa);
#else
sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
#endif
}
}
return NULL;
}
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
{
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY};
size_t needed;
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET);
if (pfRoute < 0)
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0)
return false;
{
struct timeval timeout = {1, 0};
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
}
FF_AUTO_FREE char* buf = malloc(needed);
int pid = getpid();
struct {
struct rt_msghdr hdr;
struct sockaddr_in dst;
uint8_t data[512];
} rtmsg = {
.hdr = {
.rtm_type = RTM_GET,
.rtm_flags = RTF_UP | RTF_GATEWAY,
.rtm_version = RTM_VERSION,
.rtm_addrs = RTA_DST | RTA_IFP,
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
.rtm_pid = pid,
.rtm_seq = 1,
},
.dst = {
.sin_family = AF_INET,
#ifndef __sun
.sin_len = sizeof(rtmsg.dst),
#endif
},
};
if (write(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen) != rtmsg.hdr.rtm_msglen)
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
return false;
while (read(pfRoute, &rtmsg, sizeof(rtmsg)) > 0)
char* lim = buf + needed;
struct rt_msghdr* rtm;
for (char* next = buf; next < lim; next += rtm->rtm_msglen)
{
if (rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid)
rtm = (struct rt_msghdr *)next;
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET))
{
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
if (sdl
#ifndef __sun
&& sdl->sdl_len
#endif
)
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
if (sdl && sdl->sdl_family == AF_LINK)
{
assert(sdl->sdl_nlen <= IF_NAMESIZE);
memcpy(iface, sdl->sdl_data, sdl->sdl_nlen);
iface[sdl->sdl_nlen] = '\0';
*ifIndex = sdl->sdl_index;
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
result->ifName[sdl->sdl_nlen] = '\0';
result->ifIndex = sdl->sdl_index;
// Get the preferred source address
struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(rtm, RTA_IFA);
if (src && src->sin_family == AF_INET)
result->preferredSourceAddrV4 = src->sin_addr.s_addr;
return true;
}
return false;
}
}
return false;
}
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
{
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY};
size_t needed;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0)
return false;
FF_AUTO_FREE char* buf = malloc(needed);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
return false;
char* lim = buf + needed;
struct rt_msghdr* rtm;
for (char* next = buf; next < lim; next += rtm->rtm_msglen)
{
rtm = (struct rt_msghdr *)next;
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET6))
{
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
if (sdl && sdl->sdl_family == AF_LINK)
{
assert(sdl->sdl_nlen <= IF_NAMESIZE);
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
result->ifName[sdl->sdl_nlen] = '\0';
result->ifIndex = sdl->sdl_index;
return true;
}
}
}
return false;
}
+35
View File
@@ -0,0 +1,35 @@
#include "netif.h"
#include "common/io/io.h"
#include <net/if.h>
#include <stdio.h>
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
{
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/route", "r");
if (!netRoute) return false;
// skip first line
FF_UNUSED(fscanf(netRoute, "%*[^\n]\n"));
unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu, ...
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", result->ifName, &destination) == 2)
{
if (destination != 0) continue;
result->ifIndex = if_nametoindex(result->ifName);
// TODO: Get the preferred source address
return true;
}
result->ifName[0] = '0';
return false;
}
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
{
// TODO: AF_INET6
FF_UNUSED(result);
return false;
}
+55 -6
View File
@@ -11,9 +11,8 @@
// loosely based on Haiku's src/bin/network/route/route.cpp
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
{
// TODO: AF_INET6
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET);
if (pfRoute < 0)
return false;
@@ -42,8 +41,11 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
while (interface < end) {
if (interface->ifr_route.flags & RTF_DEFAULT) {
strlcpy(iface, interface->ifr_name, IF_NAMESIZE);
*ifIndex = if_nametoindex(interface->ifr_name);
// interface->ifr_metric?
strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
result->ifIndex = if_nametoindex(interface->ifr_name);
if (interface->ifr_route.source)
result->preferredSourceAddrV4 = ((struct sockaddr_in*)interface->ifr_route.source)->sin_addr.s_addr;
return true;
}
@@ -55,9 +57,56 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
if (interface->ifr_route.gateway != NULL)
addressSize += interface->ifr_route.gateway->sa_len;
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE
+ sizeof(struct route_entry) + addressSize);
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
}
return false;
}
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
{
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET6);
if (pfRoute < 0)
return false;
struct ifconf config;
config.ifc_len = sizeof(config.ifc_value);
if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0)
return false;
int size = config.ifc_value;
if (size <= 0)
return false;
FF_AUTO_FREE void *buffer = malloc((size_t) size);
if (buffer == NULL) {
return false;
}
config.ifc_len = size;
config.ifc_buf = buffer;
if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
return false;
struct ifreq *interface = (struct ifreq*)buffer;
struct ifreq *end = (struct ifreq*)((uint8_t*)buffer + size);
while (interface < end) {
if (interface->ifr_route.flags & RTF_DEFAULT) {
strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
result->ifIndex = if_nametoindex(interface->ifr_name);
return true;
}
size_t addressSize = 0;
if (interface->ifr_route.destination != NULL)
addressSize += interface->ifr_route.destination->sa_len;
if (interface->ifr_route.mask != NULL)
addressSize += interface->ifr_route.mask->sa_len;
if (interface->ifr_route.gateway != NULL)
addressSize += interface->ifr_route.gateway->sa_len;
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
}
return false;
}
+420 -14
View File
@@ -1,26 +1,432 @@
#include "netif.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include "util/debug.h"
#include <arpa/inet.h>
#include <linux/rtnetlink.h>
#include <net/if.h>
#include <stdio.h>
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
{
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/route", "r");
if (!netRoute) return false;
FF_DEBUG("Starting IPv4 default route detection");
// skip first line
FF_UNUSED(fscanf(netRoute, "%*[^\n]\n"));
unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu,
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", iface, &destination) == 2)
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sock_fd < 0)
{
if (destination != 0) continue;
*ifIndex = if_nametoindex(iface);
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
return false;
}
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
unsigned pid = (unsigned) getpid();
FF_DEBUG("Process PID: %u", pid);
// Bind socket
struct sockaddr_nl addr = {
.nl_family = AF_NETLINK,
.nl_pid = 0, // Let kernel choose PID
.nl_groups = 0, // No multicast groups
};
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
return false;
}
FF_DEBUG("Successfully bound socket");
struct __attribute__((__packed__)) {
struct nlmsghdr nlh;
struct rtmsg rtm;
struct rtattr rta;
uint32_t table;
} req = {
// Netlink message header
.nlh = {
.nlmsg_len = sizeof(req),
.nlmsg_type = RTM_GETROUTE,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
.nlmsg_seq = 1,
.nlmsg_pid = pid,
},
// Route message
.rtm = {
.rtm_family = AF_INET,
.rtm_dst_len = 0, // Match all destinations
.rtm_src_len = 0, // Match all sources
.rtm_tos = 0,
.rtm_table = RT_TABLE_UNSPEC,
.rtm_protocol = RTPROT_UNSPEC,
.rtm_scope = RT_SCOPE_UNIVERSE,
.rtm_type = RTN_UNSPEC,
.rtm_flags = 0,
},
// Route attribute for main table
.rta = {
.rta_len = RTA_LENGTH(sizeof(uint32_t)),
.rta_type = RTA_TABLE,
},
.table = RT_TABLE_MAIN,
};
struct sockaddr_nl dest_addr = {
.nl_family = AF_NETLINK,
.nl_pid = 0, // Kernel
.nl_groups = 0, // No multicast groups
};
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0,
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
if (sent != sizeof(req)) {
FF_DEBUG("Failed to send netlink request: sent=%zd, expected=%zu", sent, sizeof(req));
return false;
}
FF_DEBUG("Sent netlink request: %zd bytes", sent);
struct sockaddr_nl src_addr = {};
socklen_t src_addr_len = sizeof(src_addr);
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
uint32_t minMetric = UINT32_MAX;
FF_MAYBE_UNUSED int routeCount = 0;
while (true)
{
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
(struct sockaddr*)&src_addr, &src_addr_len);
if (received < 0) {
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
return false;
}
if (received >= (ssize_t)sizeof(buffer)) {
FF_DEBUG("Received truncated message: received %zd, bufsize %zu", received, sizeof(buffer));
return false;
}
FF_DEBUG("Received netlink response: %zd bytes", received);
if (received == 0) {
FF_DEBUG("Received zero-length netlink response, ending processing");
break;
}
struct {
uint32_t metric;
uint32_t ifindex;
uint32_t prefsrc;
} entry;
for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
NLMSG_OK(nlh, received);
nlh = NLMSG_NEXT(nlh, received))
{
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid)
continue;
if (nlh->nlmsg_type == NLMSG_DONE)
{
FF_DEBUG("Received NLMSG_DONE, processed %d routes", routeCount);
goto exit;
}
if (nlh->nlmsg_type == NLMSG_ERROR) {
FF_DEBUG("Netlink reports error: %s", strerror(-((struct nlmsgerr*)NLMSG_DATA(nlh))->error));
continue;
}
if (nlh->nlmsg_type != RTM_NEWROUTE) {
FF_DEBUG("Skipping non-route message: type=%d", nlh->nlmsg_type);
continue;
}
routeCount++;
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
if (rtm->rtm_family != AF_INET) {
FF_DEBUG("Skipping non-IPv4 route #%d (family=%d)", routeCount, rtm->rtm_family);
continue;
}
if (rtm->rtm_dst_len != 0) {
FF_DEBUG("Skipping non-default route #%d (dst_len=%d)", routeCount, rtm->rtm_dst_len);
continue;
}
FF_DEBUG("Processing IPv4 default route candidate #%d", routeCount);
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
// Parse route attributes
size_t rtm_len = RTM_PAYLOAD(nlh);
for (struct rtattr* rta = RTM_RTA(rtm);
RTA_OK(rta, rtm_len);
rta = RTA_NEXT(rta, rtm_len))
{
if (RTA_PAYLOAD(rta) < sizeof(uint32_t))
continue; // Skip invalid attributes
uint32_t rta_data = *(uint32_t*) RTA_DATA(rta);
switch (rta->rta_type) {
case RTA_DST:
FF_DEBUG("Unexpected RTA_DST: %s (len=%u)", inet_ntoa((struct in_addr) { .s_addr = rta_data }), rtm->rtm_dst_len);
goto next;
case RTA_OIF:
entry.ifindex = rta_data;
FF_DEBUG("Found interface index: %u", entry.ifindex);
break;
case RTA_GATEWAY:
FF_DEBUG("Found gateway: %s", inet_ntoa(*(struct in_addr*)&rta_data));
if (rta_data == 0) goto next;
break;
case RTA_PRIORITY:
FF_DEBUG("Found metric: %u", rta_data);
if (rta_data >= minMetric) goto next;
entry.metric = rta_data;
break;
case RTA_PREFSRC:
entry.prefsrc = rta_data;
FF_DEBUG("Found preferred source: %s", inet_ntoa(*(struct in_addr*)&rta_data));
break;
}
}
if (entry.ifindex == 0 || entry.metric >= minMetric)
{
next:
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
continue;
}
minMetric = entry.metric;
result->ifIndex = entry.ifindex;
FF_DEBUG("Updated best route: ifindex=%u, metric=%u, prefsrc=%x", entry.ifindex, entry.metric, entry.prefsrc);
result->preferredSourceAddrV4 = entry.prefsrc;
if (minMetric == 0)
{
FF_DEBUG("Found zero metric route, stopping further processing");
break; // Stop processing if we found a zero metric route
}
}
}
exit:
if (minMetric < UINT32_MAX)
{
if_indextoname(result->ifIndex, result->ifName);
FF_DEBUG("Found default IPv4 route: interface=%s, index=%u, metric=%u", result->ifName, result->ifIndex, minMetric);
return true;
}
FF_DEBUG("No IPv4 default route found");
return false;
}
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
{
FF_DEBUG("Starting IPv6 default route detection");
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
if (sock_fd < 0)
{
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
return false;
}
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
unsigned pid = (unsigned) getpid();
FF_DEBUG("Process PID: %u", pid);
// Bind socket
struct sockaddr_nl addr = {
.nl_family = AF_NETLINK,
.nl_pid = 0, // Let kernel choose PID
.nl_groups = 0, // No multicast groups
};
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
return false;
}
FF_DEBUG("Successfully bound socket");
struct __attribute__((__packed__)) {
struct nlmsghdr nlh;
struct rtmsg rtm;
struct rtattr rta;
uint32_t table;
} req = {
// Netlink message header
.nlh = {
.nlmsg_len = sizeof(req),
.nlmsg_type = RTM_GETROUTE,
.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
.nlmsg_seq = 1,
.nlmsg_pid = pid,
},
// Route message
.rtm = {
.rtm_family = AF_INET6, // IPv6 instead of IPv4
.rtm_dst_len = 0, // Match all destinations
.rtm_src_len = 0, // Match all sources
.rtm_tos = 0,
.rtm_table = RT_TABLE_UNSPEC,
.rtm_protocol = RTPROT_UNSPEC,
.rtm_scope = RT_SCOPE_UNIVERSE,
.rtm_type = RTN_UNSPEC,
.rtm_flags = 0,
},
// Route attribute for main table
.rta = {
.rta_len = RTA_LENGTH(sizeof(uint32_t)),
.rta_type = RTA_TABLE,
},
.table = RT_TABLE_MAIN,
};
struct sockaddr_nl dest_addr = {
.nl_family = AF_NETLINK,
.nl_pid = 0, // Kernel
.nl_groups = 0, // No multicast groups
};
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0,
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
if (sent != sizeof(req)) {
FF_DEBUG("Failed to send netlink request: sent=%zd, expected=%zu", sent, sizeof(req));
return false;
}
FF_DEBUG("Sent netlink request: %zd bytes", sent);
struct sockaddr_nl src_addr = {};
socklen_t src_addr_len = sizeof(src_addr);
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
uint32_t minMetric = UINT32_MAX;
FF_MAYBE_UNUSED int routeCount = 0;
while (true)
{
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
(struct sockaddr*)&src_addr, &src_addr_len);
if (received < 0) {
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
return false;
}
if (received >= (ssize_t)sizeof(buffer)) {
FF_DEBUG("Received truncated message: received %zd, bufsize %zu", received, sizeof(buffer));
return false;
}
FF_DEBUG("Received netlink response: %zd bytes", received);
if (received == 0) {
FF_DEBUG("Received zero-length netlink response, ending processing");
break;
}
struct {
uint32_t metric;
uint32_t ifindex;
} entry;
for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
NLMSG_OK(nlh, received);
nlh = NLMSG_NEXT(nlh, received))
{
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid)
continue;
if (nlh->nlmsg_type == NLMSG_DONE)
{
FF_DEBUG("Received NLMSG_DONE, processed %d routes", routeCount);
goto exit;
}
if (nlh->nlmsg_type == NLMSG_ERROR) {
FF_DEBUG("Netlink reports error: %s", strerror(-((struct nlmsgerr*)NLMSG_DATA(nlh))->error));
continue;
}
if (nlh->nlmsg_type != RTM_NEWROUTE) {
FF_DEBUG("Skipping non-route message: type=%d", nlh->nlmsg_type);
continue;
}
routeCount++;
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
if (rtm->rtm_family != AF_INET6) {
FF_DEBUG("Skipping non-IPv6 route #%d (family=%d)", routeCount, rtm->rtm_family);
continue;
}
if (rtm->rtm_dst_len != 0) {
FF_DEBUG("Skipping non-default route #%d (dst_len=%d)", routeCount, rtm->rtm_dst_len);
continue;
}
FF_DEBUG("Processing IPv6 default route candidate #%d", routeCount);
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
// Parse route attributes
size_t rtm_len = RTM_PAYLOAD(nlh);
for (struct rtattr* rta = RTM_RTA(rtm);
RTA_OK(rta, rtm_len);
rta = RTA_NEXT(rta, rtm_len))
{
switch (rta->rta_type) {
case RTA_DST:
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
FF_MAYBE_UNUSED char str[INET6_ADDRSTRLEN];
FF_DEBUG("Unexpected RTA_DST: %s", inet_ntop(AF_INET6, RTA_DATA(rta), str, sizeof(str)));
goto next;
}
break;
case RTA_OIF:
if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) {
entry.ifindex = *(uint32_t*) RTA_DATA(rta);
FF_DEBUG("Found interface index: %u", entry.ifindex);
}
break;
case RTA_GATEWAY:
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
struct in6_addr* gw = (struct in6_addr*) RTA_DATA(rta);
if (IN6_IS_ADDR_UNSPECIFIED(gw)) goto next;
FF_MAYBE_UNUSED char str[INET6_ADDRSTRLEN];
FF_DEBUG("Found gateway: %s", inet_ntop(AF_INET6, gw, str, sizeof(str)));
}
break;
case RTA_PRIORITY:
if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) {
uint32_t metric = *(uint32_t*) RTA_DATA(rta);
FF_DEBUG("Found metric: %u", metric);
if (metric >= minMetric) goto next;
entry.metric = metric;
}
break;
}
}
if (entry.ifindex == 0 || entry.metric >= minMetric)
{
next:
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
continue;
}
minMetric = entry.metric;
result->ifIndex = entry.ifindex;
FF_DEBUG("Updated best route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
if (minMetric == 0)
{
FF_DEBUG("Found zero metric route, stopping further processing");
break; // Stop processing if we found a zero metric route
}
}
}
exit:
if (minMetric < UINT32_MAX)
{
if_indextoname(result->ifIndex, result->ifName);
FF_DEBUG("Found default IPv6 route: interface=%s, index=%u, metric=%u", result->ifName, result->ifIndex, minMetric);
return true;
}
FF_DEBUG("No IPv6 default route found");
return false;
}
+88 -12
View File
@@ -1,27 +1,103 @@
#include "netif.h"
#include "util/mallocHelper.h"
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
#include <iphlpapi.h>
bool ffNetifGetDefaultRouteImpl(FF_MAYBE_UNUSED char* iface/* unsupported */, uint32_t* ifIndex)
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
{
ULONG size = 0;
if (GetIpForwardTable(NULL, &size, TRUE) != ERROR_INSUFFICIENT_BUFFER)
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable)))
return false;
FF_AUTO_FREE MIB_IPFORWARDTABLE* pIpForwardTable = (MIB_IPFORWARDTABLE*) malloc(size);
if (GetIpForwardTable(pIpForwardTable, &size, TRUE) != ERROR_SUCCESS)
return false;
bool foundDefault = false;
uint32_t smallestMetric = UINT32_MAX;
for (uint32_t i = 0; i < pIpForwardTable->dwNumEntries; ++i)
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
{
MIB_IPFORWARDROW* ipForwardRow = &pIpForwardTable->table[i];
if (ipForwardRow->dwForwardDest == 0 && ipForwardRow->dwForwardMask == 0)
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
if (row->DestinationPrefix.PrefixLength == 0 &&
row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET &&
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0)
{
*ifIndex = ipForwardRow->dwForwardIfIndex;
break;
MIB_IF_ROW2 ifRow = {
.InterfaceIndex = row->InterfaceIndex,
};
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp)
{
MIB_IPINTERFACE_ROW ipInterfaceRow = {
.Family = AF_INET,
.InterfaceIndex = row->InterfaceIndex,
};
uint32_t realMetric = row->Metric /* Metric offset */;
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow)))
realMetric += ipInterfaceRow.Metric /* Interface metric */;
if (realMetric < smallestMetric)
{
smallestMetric = realMetric;
result->ifIndex = row->InterfaceIndex;
foundDefault = true;
break;
}
}
}
}
return true;
FreeMibTable(pIpForwardTable);
return foundDefault;
}
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
{
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable)))
return false;
bool foundDefault = false;
uint32_t smallestMetric = UINT32_MAX;
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
{
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
if (row->DestinationPrefix.PrefixLength == 0 &&
row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr))
{
MIB_IF_ROW2 ifRow = {
.InterfaceIndex = row->InterfaceIndex,
};
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp)
{
MIB_IPINTERFACE_ROW ipInterfaceRow = {
.Family = AF_INET6,
.InterfaceIndex = row->InterfaceIndex,
};
uint32_t realMetric = row->Metric /* Metric offset */;
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow)))
realMetric += ipInterfaceRow.Metric /* Interface metric */;
if (realMetric < smallestMetric)
{
smallestMetric = realMetric;
result->ifIndex = row->InterfaceIndex;
foundDefault = true;
}
}
}
}
FreeMibTable(pIpForwardTable);
return foundDefault;
}
@@ -7,14 +7,16 @@
#include <minwindef.h>
#endif
struct addrinfo;
typedef struct FFNetworkingState {
#ifdef _WIN32
uintptr_t sockfd;
OVERLAPPED overlapped;
#else
int sockfd;
FFstrbuf host;
FFstrbuf command;
struct addrinfo* addr;
#ifdef FF_HAVE_THREADS
FFThreadType thread;
@@ -23,7 +25,14 @@ typedef struct FFNetworkingState {
uint32_t timeout;
bool ipv6;
bool compression; // if true, HTTP content compression will be enabled if supported
bool tfo; // if true, TCP Fast Open will be attempted first, and fallback to traditional connection if it fails
} FFNetworkingState;
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers);
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer);
#ifdef FF_HAVE_ZLIB
const char* ffNetworkingLoadZlibLibrary(void);
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd);
#endif
+194
View File
@@ -0,0 +1,194 @@
#include "fastfetch.h"
#include "common/library.h"
#include "common/networking/networking.h"
#include "util/stringUtils.h"
#include "util/debug.h"
#ifdef FF_HAVE_ZLIB
#include <zlib.h>
struct FFZlibLibrary
{
FF_LIBRARY_SYMBOL(inflateInit2_)
FF_LIBRARY_SYMBOL(inflate)
FF_LIBRARY_SYMBOL(inflateEnd)
FF_LIBRARY_SYMBOL(inflateGetHeader)
bool inited;
} zlibData;
const char* ffNetworkingLoadZlibLibrary(void)
{
if (!zlibData.inited)
{
zlibData.inited = true;
FF_LIBRARY_LOAD(zlib, "dlopen libz failed",
#ifdef _WIN32
"zlib1"
#else
"libz"
#endif
FF_LIBRARY_EXTENSION, 2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateInit2_)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflate)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateEnd)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateGetHeader)
zlib = NULL; // don't auto dlclose
}
return zlibData.ffinflateEnd == NULL ? "Failed to load libz" : NULL;
}
// Try to pre-read gzip header to determine uncompressed size
static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize)
{
// gzip file format: http://www.zlib.org/rfc-gzip.html
if (dataSize < 10 || ((const uint8_t*)data)[0] != 0x1f || ((const uint8_t*)data)[1] != 0x8b)
return 0;
// Uncompressed size in gzip format is stored in the last 4 bytes, but only valid if data is less than 4GB
if (dataSize > 18) {
// Get ISIZE value from the end of file (little endian)
const uint8_t* tail = (const uint8_t*)data + dataSize - 4;
uint32_t uncompressedSize = (uint32_t) tail[0] | ((uint32_t) tail[1] << 8u) | ((uint32_t) tail[2] << 16u) | ((uint32_t) tail[3] << 24u);
// For valid gzip files, this value is the length of the uncompressed data modulo 2^32
if (uncompressedSize > 0) {
FF_DEBUG("Read uncompressed size from GZIP trailer: %u bytes", uncompressedSize);
// Add some margin to the estimated size for safety
return uncompressedSize + 64;
}
}
// If unable to get size from trailer or size is 0, use estimated value
// Typically, text data compression ratio is between 3-5x, we use the larger value
uint32_t estimatedSize = dataSize * 5;
FF_DEBUG("Unable to read exact uncompressed size, estimated as 5x of compressed data: %u bytes", estimatedSize);
return estimatedSize;
}
// Decompress gzip content
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
{
// Calculate header size
uint32_t headerSize = (uint32_t) (headerEnd - buffer->chars);
*headerEnd = '\0'; // Replace delimiter with null character for easier processing
// Ensure Content-Encoding is in response headers, not in response body
bool hasGzip = strcasestr(buffer->chars, "\nContent-Encoding: gzip") != NULL;
*headerEnd = '\r'; // Restore delimiter
if (!hasGzip) {
FF_DEBUG("No gzip compressed content detected, skipping decompression");
return true;
}
FF_DEBUG("Gzip compressed content detected, preparing for decompression");
const char* bodyStart = headerEnd + 4; // Skip delimiter
// Calculate compressed content size
uint32_t compressedSize = buffer->length - headerSize - 4;
if (compressedSize <= 0) {
// No content to decompress
FF_DEBUG("Compressed content size is 0, skipping decompression");
return true;
}
// Check if content is actually in gzip format (gzip header magic is 0x1f 0x8b)
if (compressedSize < 2 || (uint8_t)bodyStart[0] != 0x1f || (uint8_t)bodyStart[1] != 0x8b) {
FF_DEBUG("Content is not valid gzip format, skipping decompression");
return false;
}
// Predict uncompressed size
uint32_t estimatedSize = guessGzipOutputSize(bodyStart, compressedSize);
// Create decompression buffer with estimated size
FF_STRBUF_AUTO_DESTROY decompressedBuffer = ffStrbufCreateA(estimatedSize > 0 ? estimatedSize : compressedSize * 5);
FF_DEBUG("Created decompression buffer: %u bytes", decompressedBuffer.allocated);
// Initialize decompression
z_stream zs = {
.zalloc = Z_NULL,
.zfree = Z_NULL,
.opaque = Z_NULL,
.avail_in = (uInt)compressedSize,
.next_in = (Bytef*)bodyStart,
.avail_out = (uInt)ffStrbufGetFree(&decompressedBuffer),
.next_out = (Bytef*)decompressedBuffer.chars,
};
// Initialize decompression engine
if (zlibData.ffinflateInit2_(&zs, 16 + MAX_WBITS, ZLIB_VERSION, (int)sizeof(z_stream)) != Z_OK) {
FF_DEBUG("Failed to initialize decompression engine");
return false;
}
uInt availableOut = zs.avail_out;
// Perform decompression
int result = zlibData.ffinflate(&zs, Z_FINISH);
// If output buffer is insufficient, try to extend buffer
while (result == Z_BUF_ERROR || (result != Z_STREAM_END && zs.avail_out == 0))
{
FF_DEBUG("Output buffer insufficient, trying to extend");
// Save already decompressed data amount
uint32_t alreadyDecompressed = (uint32_t)(availableOut - zs.avail_out);
decompressedBuffer.length += alreadyDecompressed;
decompressedBuffer.chars[decompressedBuffer.length] = '\0'; // Ensure null-terminated string
ffStrbufEnsureFree(&decompressedBuffer, decompressedBuffer.length / 2);
// Set output parameters to point to new buffer
zs.avail_out = (uInt)ffStrbufGetFree(&decompressedBuffer);
zs.next_out = (Bytef*)(decompressedBuffer.chars + decompressedBuffer.length);
availableOut = zs.avail_out;
// Decompress again
result = zlibData.ffinflate(&zs, Z_FINISH);
}
zlibData.ffinflateEnd(&zs);
// Calculate decompressed size
uint32_t decompressedSize = (uint32_t)(availableOut - zs.avail_out);
decompressedBuffer.length += decompressedSize;
decompressedBuffer.chars[decompressedSize] = '\0'; // Ensure null-terminated string
FF_DEBUG("Successfully decompressed %u bytes compressed data to %u bytes", compressedSize, decompressedBuffer.length);
// Modify Content-Length header and remove Content-Encoding header
FF_STRBUF_AUTO_DESTROY newBuffer = ffStrbufCreateA(headerSize + decompressedSize + 64);
char* line = NULL;
size_t len = 0;
while (ffStrbufGetline(&line, &len, buffer))
{
if (ffStrStartsWithIgnCase(line, "Content-Encoding:"))
{
continue;
}
else if (ffStrStartsWithIgnCase(line, "Content-Length:"))
{
ffStrbufAppendF(&newBuffer, "Content-Length: %u\r\n", decompressedSize);
continue;
}
else if (line[0] == '\r')
{
ffStrbufAppendS(&newBuffer, "\r\n");
ffStrbufGetlineRestore(&line, &len, buffer);
break;
}
ffStrbufAppendS(&newBuffer, line);
ffStrbufAppendC(&newBuffer, '\n');
}
ffStrbufAppend(&newBuffer, &decompressedBuffer);
ffStrbufDestroy(buffer);
ffStrbufInitMove(buffer, &newBuffer);
return true;
}
#endif // FF_HAVE_ZLIB
+500
View File
@@ -0,0 +1,500 @@
#include "fastfetch.h"
#include "common/networking/networking.h"
#include "common/time.h"
#include "common/library.h"
#include "util/stringUtils.h"
#include "util/mallocHelper.h"
#include "util/debug.h"
#include <unistd.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h> // For FreeBSD
#include <netinet/tcp.h>
#include <errno.h>
#include <fcntl.h>
static const char* tryNonThreadingFastPath(FFNetworkingState* state)
{
#if defined(TCP_FASTOPEN) || __APPLE__
if (!state->tfo)
{
#if __linux__ || __GNU__
// Linux doesn't support sendto() on unconnected sockets
FF_DEBUG("TCP Fast Open disabled, skipping");
return "TCP Fast Open disabled";
#endif
}
else
{
FF_DEBUG("Attempting to use TCP Fast Open to connect");
#ifndef __APPLE__ // On macOS, TCP_FASTOPEN doesn't seem to be needed
// Set TCP Fast Open
#if __linux__ || __GNU__
int flag = 5; // the queue length of pending packets
#else
int flag = 1; // enable TCP Fast Open
#endif
if (setsockopt(state->sockfd, IPPROTO_TCP,
#ifdef __APPLE__
// https://github.com/rust-lang/libc/pull/3135
0x218 // TCP_FASTOPEN_FORCE_ENABLE
#else
TCP_FASTOPEN
#endif
, &flag, sizeof(flag)) != 0) {
FF_DEBUG("Failed to set TCP_FASTOPEN option: %s", strerror(errno));
return "setsockopt(TCP_FASTOPEN) failed";
} else {
#if __linux__ || __GNU__
FF_DEBUG("Successfully set TCP_FASTOPEN option, queue length: %d", flag);
#elif defined(__APPLE__)
FF_DEBUG("Successfully set TCP_FASTOPEN_FORCE_ENABLE option");
#else
FF_DEBUG("Successfully set TCP_FASTOPEN option");
#endif
}
#endif
}
#ifndef __APPLE__
FF_DEBUG("Using sendto() + MSG_DONTWAIT to send %u bytes of data", state->command.length);
ssize_t sent = sendto(state->sockfd,
state->command.chars,
state->command.length,
#ifdef MSG_FASTOPEN
MSG_FASTOPEN |
#endif
#ifdef MSG_NOSIGNAL
MSG_NOSIGNAL |
#endif
MSG_DONTWAIT,
state->addr->ai_addr,
state->addr->ai_addrlen);
#else
if (fcntl(state->sockfd, F_SETFL, O_NONBLOCK) == -1) {
FF_DEBUG("fcntl(F_SETFL) failed: %s", strerror(errno));
return "fcntl(F_SETFL) failed";
}
FF_DEBUG("Using connectx() to send %u bytes of data", state->command.length);
// Use connectx to establish connection and send data in one call
size_t sent;
if (connectx(state->sockfd,
&(sa_endpoints_t) {
.sae_dstaddr = state->addr->ai_addr,
.sae_dstaddrlen = state->addr->ai_addrlen,
},
SAE_ASSOCID_ANY, state->tfo ? CONNECT_DATA_IDEMPOTENT : 0,
&(struct iovec) {
.iov_base = state->command.chars,
.iov_len = state->command.length,
}, 1, &sent, NULL) != 0) sent = 0;
if (fcntl(state->sockfd, F_SETFL, 0) == -1) {
FF_DEBUG("fcntl(F_SETFL) failed: %s", strerror(errno));
return "fcntl(F_SETFL) failed";
}
#endif
if (sent > 0 || (errno == EAGAIN || errno == EWOULDBLOCK
#ifdef __APPLE__
// On macOS EINPROGRESS means the connection cannot be completed immediately
// On Linux, it means the TFO cookie is not available locally
|| errno == EINPROGRESS
#endif
))
{
FF_DEBUG(
#ifdef __APPLE__
"connectx()"
#else
"sendto()"
#endif
" %s (sent=%zd, errno=%d: %s)", errno == 0 ? "succeeded" : "was in progress",
sent, errno, strerror(errno));
freeaddrinfo(state->addr);
state->addr = NULL;
ffStrbufDestroy(&state->command);
return NULL;
}
FF_DEBUG(
#ifdef __APPLE__
"connectx()"
#else
"sendto()"
#endif
" failed: %s (errno=%d)", strerror(errno), errno);
#ifdef __APPLE__
return "connectx() failed";
#else
return "sendto() failed";
#endif
#else
FF_UNUSED(state);
return "TFO support is not available";
#endif
}
// Traditional connect and send function
static const char* connectAndSend(FFNetworkingState* state)
{
const char* ret = NULL;
FF_DEBUG("Using traditional connection method to connect");
FF_DEBUG("Attempting connect() to server...");
if(connect(state->sockfd, state->addr->ai_addr, state->addr->ai_addrlen) == -1)
{
FF_DEBUG("connect() failed: %s (errno=%d)", strerror(errno), errno);
ret = "connect() failed";
goto error;
}
FF_DEBUG("connect() succeeded");
FF_DEBUG("Attempting to send %u bytes of data...", state->command.length);
if(send(state->sockfd, state->command.chars, state->command.length, 0) < 0)
{
FF_DEBUG("send() failed: %s (errno=%d)", strerror(errno), errno);
ret = "send() failed";
goto error;
}
FF_DEBUG("Data sent successfully");
goto exit;
error:
FF_DEBUG("Error occurred, closing socket");
close(state->sockfd);
state->sockfd = -1;
exit:
FF_DEBUG("Releasing address info and other resources");
freeaddrinfo(state->addr);
state->addr = NULL;
ffStrbufDestroy(&state->command);
return ret;
}
FF_THREAD_ENTRY_DECL_WRAPPER(connectAndSend, FFNetworkingState*);
// Parallel DNS resolution and socket creation
static const char* initNetworkingState(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
FF_DEBUG("Initializing network connection state: host=%s, path=%s", host, path);
// Initialize command and host information
ffStrbufInitA(&state->command, 64);
ffStrbufAppendS(&state->command, "GET ");
ffStrbufAppendS(&state->command, path);
ffStrbufAppendS(&state->command, " HTTP/1.0\nHost: ");
ffStrbufAppendS(&state->command, host);
ffStrbufAppendS(&state->command, "\r\n");
// Add extra optimized HTTP headers
ffStrbufAppendS(&state->command, "Connection: close\r\n"); // Explicitly tell the server we don't need to keep the connection
// If compression needs to be enabled
if (state->compression) {
FF_DEBUG("Enabling HTTP content compression");
ffStrbufAppendS(&state->command, "Accept-Encoding: gzip\r\n");
}
ffStrbufAppendS(&state->command, headers);
ffStrbufAppendS(&state->command, "\r\n");
#ifdef FF_HAVE_THREADS
state->thread = 0;
FF_DEBUG("Thread ID initialized to 0");
#endif
const char* ret = NULL;
struct addrinfo hints = {
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_NUMERICSERV
};
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
// Use AI_NUMERICSERV flag to indicate the service is a numeric port, reducing parsing time
if(getaddrinfo(host, "80", &hints, &state->addr) != 0)
{
FF_DEBUG("getaddrinfo() failed: %s", gai_strerror(errno));
ret = "getaddrinfo() failed";
goto error;
}
FF_DEBUG("Address resolution successful");
FF_DEBUG("Creating socket");
state->sockfd = socket(state->addr->ai_family, state->addr->ai_socktype, state->addr->ai_protocol);
if(state->sockfd == -1)
{
FF_DEBUG("socket() failed: %s (errno=%d)", strerror(errno), errno);
ret = "socket() failed";
goto error;
}
FF_DEBUG("Socket creation successful: fd=%d", state->sockfd);
int flag = 1;
#ifdef TCP_NODELAY
// Disable Nagle's algorithm to reduce small packet transmission delay
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)) != 0) {
FF_DEBUG("Failed to set TCP_NODELAY: %s", strerror(errno));
} else {
FF_DEBUG("Successfully disabled Nagle's algorithm");
}
#endif
#ifdef TCP_QUICKACK
// Set TCP_QUICKACK option to avoid delayed acknowledgments
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_QUICKACK, &flag, sizeof(flag)) != 0) {
FF_DEBUG("Failed to set TCP_QUICKACK: %s", strerror(errno));
} else {
FF_DEBUG("Successfully enabled TCP quick acknowledgment");
}
#endif
if (state->timeout > 0)
{
FF_DEBUG("Setting connection timeout: %u ms", state->timeout);
FF_MAYBE_UNUSED uint32_t sec = state->timeout / 1000;
if (sec == 0) sec = 1;
#ifdef TCP_CONNECTIONTIMEOUT
FF_DEBUG("Using TCP_CONNECTIONTIMEOUT: %u seconds", sec);
setsockopt(state->sockfd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &sec, sizeof(sec));
#elif defined(TCP_KEEPINIT)
FF_DEBUG("Using TCP_KEEPINIT: %u seconds", sec);
setsockopt(state->sockfd, IPPROTO_TCP, TCP_KEEPINIT, &sec, sizeof(sec));
#elif defined(TCP_USER_TIMEOUT)
FF_DEBUG("Using TCP_USER_TIMEOUT: %u milliseconds", state->timeout);
setsockopt(state->sockfd, IPPROTO_TCP, TCP_USER_TIMEOUT, &state->timeout, sizeof(state->timeout));
#else
FF_DEBUG("Current platform does not support TCP connection timeout");
#endif
}
return NULL;
error:
FF_DEBUG("Error occurred during initialization");
if (state->addr != NULL)
{
FF_DEBUG("Releasing address information");
freeaddrinfo(state->addr);
state->addr = NULL;
}
if (state->sockfd > 0)
{
FF_DEBUG("Closing socket: fd=%d", state->sockfd);
close(state->sockfd);
state->sockfd = -1;
}
return ret;
}
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
FF_DEBUG("Preparing to send HTTP request: host=%s, path=%s", host, path);
if (state->compression)
{
FF_DEBUG("Compression enabled, checking if zlib is available");
#ifdef FF_HAVE_ZLIB
const char* zlibError = ffNetworkingLoadZlibLibrary();
// Only enable compression if zlib library is successfully loaded
if (zlibError == NULL)
{
FF_DEBUG("Successfully loaded zlib library, compression enabled");
} else {
FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError);
state->compression = false;
}
#else
FF_DEBUG("zlib not supported at build time, compression disabled");
state->compression = false;
#endif
}
else
{
FF_DEBUG("Compression disabled");
}
const char* initResult = initNetworkingState(state, host, path, headers);
if (initResult != NULL) {
FF_DEBUG("Initialization failed: %s", initResult);
return initResult;
}
FF_DEBUG("Network state initialization successful");
const char* tfoResult = tryNonThreadingFastPath(state);
if (tfoResult == NULL) {
FF_DEBUG("TryNonThreadingFastPath() succeeded or in progress");
return NULL;
}
FF_DEBUG("TryNonThreadingFastPath() failed: %s, trying traditional connection", tfoResult);
#ifdef FF_HAVE_THREADS
if (instance.config.general.multithreading)
{
FF_DEBUG("Multithreading mode enabled, creating connection thread");
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
if (state->thread) {
FF_DEBUG("Thread creation successful: thread=%p", (void*)(uintptr_t)state->thread);
return NULL;
}
FF_DEBUG("Thread creation failed");
} else {
FF_DEBUG("Multithreading mode disabled, connecting in main thread");
}
#endif
return connectAndSend(state);
}
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
{
FF_DEBUG("Preparing to receive HTTP response");
uint32_t timeout = state->timeout;
#ifdef FF_HAVE_THREADS
if (state->thread)
{
FF_DEBUG("Connection thread is running, waiting for it to complete (timeout=%u ms)", timeout);
if (!ffThreadJoin(state->thread, timeout)) {
FF_DEBUG("Thread join failed or timed out");
return "ffThreadJoin() failed or timeout";
}
FF_DEBUG("Thread completed successfully");
state->thread = 0;
}
#endif
if(state->sockfd == -1)
{
FF_DEBUG("Invalid socket, HTTP request might have failed");
return "ffNetworkingSendHttpRequest() failed";
}
// Set larger initial receive buffer instead of small repeated receives
int rcvbuf = 65536; // 64KB
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
#ifdef __APPLE__
// poll for the socket to be readable.
// Because of the non-blocking connectx() call, the connection might not be established yet
FF_DEBUG("Using poll() to check if socket is readable");
if (poll(&(struct pollfd) {
.fd = state->sockfd,
.events = POLLIN
}, 1, timeout > 0 ? (int) timeout : -1) == -1)
{
FF_DEBUG("poll() failed: %s (errno=%d)", strerror(errno), errno);
close(state->sockfd);
state->sockfd = -1;
return "poll() failed";
}
FF_DEBUG("Socket is readable, proceeding to receive data");
#else
if(timeout > 0)
{
FF_DEBUG("Setting receive timeout: %u ms", timeout);
struct timeval timev;
timev.tv_sec = timeout / 1000;
timev.tv_usec = (__typeof__(timev.tv_usec)) ((timeout % 1000) * 1000); //milliseconds to microseconds
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev));
}
#endif
FF_DEBUG("Starting data reception");
FF_MAYBE_UNUSED int recvCount = 0;
uint32_t contentLength = 0;
char* headerEnd = NULL;
do {
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
++recvCount, buffer->length, ffStrbufGetFree(buffer));
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, ffStrbufGetFree(buffer), MSG_WAITALL);
if (received <= 0) {
if (received == 0) {
FF_DEBUG("Connection closed (received=0)");
} else {
FF_DEBUG("Reception failed: %s (errno=%d)", strerror(errno), errno);
}
break;
}
buffer->length += (uint32_t) received;
buffer->chars[buffer->length] = '\0';
FF_DEBUG("Successfully received %zd bytes of data, total: %u bytes", received, buffer->length);
// Check if HTTP header end marker is found
if (headerEnd == NULL) {
headerEnd = memmem(buffer->chars, buffer->length, "\r\n\r\n", 4);
if (headerEnd != NULL) {
FF_DEBUG("Found HTTP header end marker, position: %ld", (long)(headerEnd - buffer->chars));
// Check for Content-Length header to pre-allocate enough memory
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
if (clHeader) {
contentLength = (uint32_t) strtoul(clHeader + 16, NULL, 10);
if (contentLength > 0) {
FF_DEBUG("Detected Content-Length: %u, pre-allocating buffer", contentLength);
// Ensure buffer is large enough, adding header size and some margin
ffStrbufEnsureFree(buffer, contentLength + 16);
FF_DEBUG("Extended receive buffer to %u bytes", buffer->length);
}
}
}
}
} while (ffStrbufGetFree(buffer) > 0);
FF_DEBUG("Closing socket: fd=%d", state->sockfd);
close(state->sockfd);
state->sockfd = -1;
if (buffer->length == 0) {
FF_DEBUG("Server response is empty");
return "Empty server response received";
}
if (headerEnd == NULL) {
FF_DEBUG("No HTTP header end marker found");
return "No HTTP header end found";
}
if (contentLength > 0 && buffer->length != contentLength + (uint32_t)(headerEnd - buffer->chars) + 4) {
FF_DEBUG("Received content length mismatches: %u != %u", buffer->length, contentLength + (uint32_t)(headerEnd - buffer->chars) + 4);
return "Content length mismatch";
}
if (ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
FF_DEBUG("Received valid HTTP 200 response, content %u bytes, total %u bytes", contentLength, buffer->length);
} else {
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
return "Invalid response";
}
// If compression was used, try to decompress
#ifdef FF_HAVE_ZLIB
if (state->compression) {
FF_DEBUG("Content received, checking if compressed");
if (!ffNetworkingDecompressGzip(buffer, headerEnd)) {
FF_DEBUG("Decompression failed or invalid compression format");
return "Failed to decompress or invalid format";
} else {
FF_DEBUG("Decompression successful or no decompression needed, total length after decompression: %u bytes", buffer->length);
}
}
#endif
return NULL;
}
+339
View File
@@ -0,0 +1,339 @@
#include <mswsock.h>
#include <ws2tcpip.h>
//Must be included after <mswsock.h>
#include "fastfetch.h"
#include "common/networking/networking.h"
#include "util/stringUtils.h"
#include "util/debug.h"
static LPFN_CONNECTEX ConnectEx;
static const char* initWsaData(WSADATA* wsaData)
{
FF_DEBUG("Initializing WinSock");
if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0) {
FF_DEBUG("WSAStartup() failed");
return "WSAStartup() failed";
}
if(LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2) {
FF_DEBUG("Invalid wsaData version found: %d.%d", LOBYTE(wsaData->wVersion), HIBYTE(wsaData->wVersion));
return "Invalid wsaData version found";
}
//Dummy socket needed for WSAIoctl
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == INVALID_SOCKET) {
FF_DEBUG("socket(AF_INET, SOCK_STREAM) failed");
return "socket(AF_INET, SOCK_STREAM) failed";
}
DWORD dwBytes;
GUID guid = WSAID_CONNECTEX;
if(WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid, sizeof(guid),
&ConnectEx, sizeof(ConnectEx),
&dwBytes, NULL, NULL) != 0) {
FF_DEBUG("WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
return "WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed";
}
closesocket(sockfd);
FF_DEBUG("WinSock initialized successfully");
return NULL;
}
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
FF_DEBUG("Preparing to send HTTP request: host=%s, path=%s", host, path);
if (state->compression)
{
#ifdef FF_HAVE_ZLIB
const char* zlibError = ffNetworkingLoadZlibLibrary();
// Only enable compression if zlib library is successfully loaded
if (zlibError == NULL)
{
FF_DEBUG("Successfully loaded zlib library, compression enabled");
} else {
FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError);
state->compression = false;
}
#else
FF_DEBUG("zlib not supported at build time, compression disabled");
state->compression = false;
#endif
}
else
{
FF_DEBUG("Compression disabled");
}
static WSADATA wsaData;
if (wsaData.wVersion == 0)
{
const char* error = initWsaData(&wsaData);
if (error != NULL)
{
wsaData.wVersion = (WORD) -1;
FF_DEBUG("WinSock initialization failed: %s", error);
return error;
}
}
else if (wsaData.wVersion == (WORD) -1)
{
FF_DEBUG("WinSock initialization previously failed");
return "initWsaData() failed before";
}
struct addrinfo* addr;
struct addrinfo hints = {
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_NUMERICSERV,
};
FF_DEBUG("Resolving address: %s (%s)", host, state->ipv6 ? "IPv6" : "IPv4");
if(getaddrinfo(host, "80", &hints, &addr) != 0)
{
FF_DEBUG("getaddrinfo() failed");
return "getaddrinfo() failed";
}
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if(state->sockfd == INVALID_SOCKET)
{
FF_DEBUG("socket() failed");
freeaddrinfo(addr);
return "socket() failed";
}
DWORD flag = 1;
#ifdef TCP_NODELAY
// Enable TCP_NODELAY to disable Nagle's algorithm
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(flag)) != 0) {
FF_DEBUG("Failed to set TCP_NODELAY: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
} else {
FF_DEBUG("Successfully disabled Nagle's algorithm");
}
#endif
// Set timeout if needed
if (state->timeout > 0) {
FF_DEBUG("Setting connection timeout: %u ms", state->timeout);
setsockopt(state->sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&state->timeout, sizeof(state->timeout));
}
//ConnectEx requires the socket to be initially bound
if((state->ipv6
? bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in6) {
.sin6_family = AF_INET6,
.sin6_addr = in6addr_any,
}, sizeof(struct sockaddr_in6))
: bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in) {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
}, sizeof(struct sockaddr_in))) != 0)
{
FF_DEBUG("bind() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
closesocket(state->sockfd);
freeaddrinfo(addr);
state->sockfd = INVALID_SOCKET;
return "bind() failed";
}
// Initialize overlapped structure for asynchronous I/O
memset(&state->overlapped, 0, sizeof(OVERLAPPED));
// Build HTTP command
FF_STRBUF_AUTO_DESTROY command = ffStrbufCreateA(64);
ffStrbufAppendS(&command, "GET ");
ffStrbufAppendS(&command, path);
ffStrbufAppendS(&command, " HTTP/1.0\nHost: ");
ffStrbufAppendS(&command, host);
ffStrbufAppendS(&command, "\r\n");
ffStrbufAppendS(&command, "Connection: close\r\n"); // Explicitly request connection closure
// Add compression support if enabled
if (state->compression) {
FF_DEBUG("Enabling HTTP content compression");
ffStrbufAppendS(&command, "Accept-Encoding: gzip\r\n");
}
ffStrbufAppendS(&command, headers);
ffStrbufAppendS(&command, "\r\n");
#ifdef TCP_FASTOPEN
if (state->tfo)
{
// Set TCP Fast Open
flag = 1;
if (setsockopt(state->sockfd, IPPROTO_TCP, TCP_FASTOPEN, (char*)&flag, sizeof(flag)) != 0) {
FF_DEBUG("Failed to set TCP_FASTOPEN option: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
} else {
FF_DEBUG("Successfully set TCP_FASTOPEN option");
}
}
else
{
FF_DEBUG("TCP Fast Open disabled");
}
#endif
FF_DEBUG("Using ConnectEx to send %u bytes of data", command.length);
DWORD sent = 0;
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int)addr->ai_addrlen,
command.chars, command.length, &sent, &state->overlapped);
freeaddrinfo(addr);
addr = NULL;
if(!result)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
FF_DEBUG("ConnectEx() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
closesocket(state->sockfd);
state->sockfd = INVALID_SOCKET;
return "ConnectEx() failed";
}
else
{
FF_DEBUG("ConnectEx() pending");
}
}
else
{
FF_DEBUG("ConnectEx() succeeded, sent %u bytes of data", (unsigned) sent);
}
// No need to cleanup state fields here since we need them in the receive function
return NULL;
}
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
{
FF_DEBUG("Preparing to receive HTTP response");
if (state->sockfd == INVALID_SOCKET)
{
FF_DEBUG("Invalid socket, HTTP request might have failed");
return "ffNetworkingSendHttpRequest() failed";
}
uint32_t timeout = state->timeout;
if (timeout > 0)
{
FF_DEBUG("WaitForSingleObject with timeout: %u ms", timeout);
if (WaitForSingleObject((HANDLE)state->sockfd, timeout) != WAIT_OBJECT_0)
{
FF_DEBUG("WaitForSingleObject failed or timed out");
CancelIo((HANDLE) state->sockfd);
closesocket(state->sockfd);
return "WaitForSingleObject(state->sockfd) failed or timeout";
}
}
DWORD transfer, flags;
if (!WSAGetOverlappedResult(state->sockfd, &state->overlapped, &transfer, TRUE, &flags))
{
FF_DEBUG("WSAGetOverlappedResult failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
closesocket(state->sockfd);
return "WSAGetOverlappedResult() failed";
}
if(timeout > 0)
{
FF_DEBUG("Setting receive timeout: %u ms", timeout);
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
}
// Set larger receive buffer for better performance
int rcvbuf = 65536; // 64KB
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&rcvbuf, sizeof(rcvbuf));
FF_DEBUG("Starting data reception");
FF_MAYBE_UNUSED int recvCount = 0;
uint32_t contentLength = 0;
char* headerEnd = NULL;
do {
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
++recvCount, buffer->length, ffStrbufGetFree(buffer));
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, (int)ffStrbufGetFree(buffer), 0);
if (received <= 0) {
if (received == 0) {
FF_DEBUG("Connection closed (received=0)");
} else {
FF_DEBUG("Reception failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
}
break;
}
buffer->length += (uint32_t) received;
buffer->chars[buffer->length] = '\0';
FF_DEBUG("Successfully received %zd bytes of data, total: %u bytes", received, buffer->length);
// Check if HTTP header end marker is found
if (headerEnd == NULL) {
headerEnd = strstr(buffer->chars, "\r\n\r\n");
if (headerEnd != NULL) {
FF_DEBUG("Found HTTP header end marker, position: %ld", (long)(headerEnd - buffer->chars));
// Check for Content-Length header to pre-allocate enough memory
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
if (clHeader) {
contentLength = (uint32_t) strtoul(clHeader + 16, NULL, 10);
if (contentLength > 0) {
FF_DEBUG("Detected Content-Length: %u, pre-allocating buffer", contentLength);
// Ensure buffer is large enough, adding header size and some margin
ffStrbufEnsureFree(buffer, contentLength + 16);
FF_DEBUG("Extended receive buffer to %u bytes", buffer->allocated);
}
}
}
}
} while (ffStrbufGetFree(buffer) > 0);
FF_DEBUG("Closing socket: fd=%u", (unsigned)state->sockfd);
closesocket(state->sockfd);
state->sockfd = INVALID_SOCKET;
if (buffer->length == 0) {
FF_DEBUG("Server response is empty");
return "Empty server response received";
}
if (headerEnd == NULL) {
FF_DEBUG("No HTTP header end marker found");
return "No HTTP header end found";
}
if (ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
FF_DEBUG("Received valid HTTP 200 response, content length: %u bytes, total length: %u bytes",
contentLength, buffer->length);
} else {
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
return "Invalid response";
}
// If compression was used, try to decompress
#ifdef FF_HAVE_ZLIB
if (state->compression) {
FF_DEBUG("Content received, checking if compressed");
if (!ffNetworkingDecompressGzip(buffer, headerEnd)) {
FF_DEBUG("Decompression failed or invalid compression format");
return "Failed to decompress or invalid format";
} else {
FF_DEBUG("Decompression successful or no decompression needed, total length after decompression: %u bytes", buffer->length);
}
}
#endif
return NULL;
}
-137
View File
@@ -1,137 +0,0 @@
#include "fastfetch.h"
#include "common/networking.h"
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h> // For FreeBSD
#include <netinet/tcp.h>
static const char* connectAndSend(FFNetworkingState* state)
{
const char* ret = NULL;
struct addrinfo* addr;
if(getaddrinfo(state->host.chars, "80", &(struct addrinfo) {
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
.ai_socktype = SOCK_STREAM,
}, &addr) != 0)
{
ret = "getaddrinfo() failed";
goto error;
}
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if(state->sockfd == -1)
{
freeaddrinfo(addr);
ret = "socket() failed";
goto error;
}
if (state->timeout > 0)
{
FF_MAYBE_UNUSED uint32_t sec = state->timeout / 1000;
if (sec == 0) sec = 1;
#ifdef TCP_CONNECTIONTIMEOUT
setsockopt(state->sockfd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &sec, sizeof(sec));
#elif defined(TCP_KEEPINIT)
setsockopt(state->sockfd, IPPROTO_TCP, TCP_KEEPINIT, &sec, sizeof(sec));
#elif defined(TCP_USER_TIMEOUT)
setsockopt(state->sockfd, IPPROTO_TCP, TCP_USER_TIMEOUT, &state->timeout, sizeof(state->timeout));
#endif
}
if(connect(state->sockfd, addr->ai_addr, addr->ai_addrlen) == -1)
{
close(state->sockfd);
freeaddrinfo(addr);
ret = "connect() failed";
goto error;
}
freeaddrinfo(addr);
if(send(state->sockfd, state->command.chars, state->command.length, 0) < 0)
{
close(state->sockfd);
ret = "send() failed";
goto error;
}
goto exit;
error:
state->sockfd = -1;
exit:
ffStrbufDestroy(&state->host);
ffStrbufDestroy(&state->command);
return ret;
}
FF_THREAD_ENTRY_DECL_WRAPPER(connectAndSend, FFNetworkingState*);
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
ffStrbufInitS(&state->host, host);
ffStrbufInitA(&state->command, 64);
ffStrbufAppendS(&state->command, "GET ");
ffStrbufAppendS(&state->command, path);
ffStrbufAppendS(&state->command, " HTTP/1.1\nHost: ");
ffStrbufAppendS(&state->command, host);
ffStrbufAppendS(&state->command, "\r\n");
ffStrbufAppendS(&state->command, headers);
ffStrbufAppendS(&state->command, "\r\n");
#ifdef FF_HAVE_THREADS
if (instance.config.general.multithreading)
{
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
return state->thread ? NULL : "ffThreadCreate(connectAndSend) failed";
}
#endif
return connectAndSend(state);
}
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
{
uint32_t timeout = state->timeout;
#ifdef FF_HAVE_THREADS
if (instance.config.general.multithreading)
{
if (!ffThreadJoin(state->thread, timeout))
return "ffThreadJoin() failed or timeout";
}
#endif
if(state->sockfd == -1)
return "ffNetworkingSendHttpRequest() failed";
if(timeout > 0)
{
struct timeval timev;
timev.tv_sec = timeout / 1000;
timev.tv_usec = (__typeof__(timev.tv_usec)) ((timeout % 1000) * 1000); //milliseconds to microseconds
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev));
}
uint32_t recvStart;
do {
recvStart = buffer->length;
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, ffStrbufGetFree(buffer), 0);
if (received <= 0) break;
buffer->length += (uint32_t) received;
buffer->chars[buffer->length] = '\0';
} while (ffStrbufGetFree(buffer) > 0 && strstr(buffer->chars + recvStart, "\r\n\r\n") == NULL);
close(state->sockfd);
if (buffer->length == 0) return "Empty server response received";
return ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n") ? NULL : "Invalid response";
}
-146
View File
@@ -1,146 +0,0 @@
#include <mswsock.h>
#include <ws2tcpip.h>
//Must be included after <mswsock.h>
#include "fastfetch.h"
#include "common/networking.h"
static LPFN_CONNECTEX ConnectEx;
static const char* initWsaData(WSADATA* wsaData)
{
if(WSAStartup(MAKEWORD(2, 2), wsaData) != 0)
return "WSAStartup() failed";
if(LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2)
return "Invalid wsaData version found";
//Dummy socket needed for WSAIoctl
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == INVALID_SOCKET)
return "socket(AF_INET, SOCK_STREAM) failed";
DWORD dwBytes;
GUID guid = WSAID_CONNECTEX;
if(WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid, sizeof(guid),
&ConnectEx, sizeof(ConnectEx),
&dwBytes, NULL, NULL) != 0)
return "WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed";
closesocket(sockfd);
return NULL;
}
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
static WSADATA wsaData;
if (wsaData.wVersion == 0)
{
const char* error = initWsaData(&wsaData);
if (error != NULL)
{
wsaData.wVersion = (WORD) -1;
return error;
}
}
else if (wsaData.wVersion == (WORD) -1)
return "initWsaData() failed before";
struct addrinfo* addr;
if(getaddrinfo(host, "80", &(struct addrinfo) {
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
.ai_socktype = SOCK_STREAM,
}, &addr) != 0)
return "getaddrinfo() failed";
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if(state->sockfd == INVALID_SOCKET)
{
freeaddrinfo(addr);
return "socket() failed";
}
//ConnectEx requires the socket to be initially bound
if((state->ipv6
? bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in6) {
.sin6_family = AF_INET6,
.sin6_addr = in6addr_any,
}, sizeof(struct sockaddr_in6))
: bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in) {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
}, sizeof(struct sockaddr_in))) != 0)
{
closesocket(state->sockfd);
freeaddrinfo(addr);
state->sockfd = INVALID_SOCKET;
return "bind() failed";
}
FF_STRBUF_AUTO_DESTROY command = ffStrbufCreateA(64);
ffStrbufAppendS(&command, "GET ");
ffStrbufAppendS(&command, path);
ffStrbufAppendS(&command, " HTTP/1.1\nHost: ");
ffStrbufAppendS(&command, host);
ffStrbufAppendS(&command, "\r\n");
ffStrbufAppendS(&command, headers);
ffStrbufAppendS(&command, "\r\n");
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int)addr->ai_addrlen, command.chars, command.length, NULL, &state->overlapped);
freeaddrinfo(addr);
if(!result && WSAGetLastError() != WSA_IO_PENDING)
{
closesocket(state->sockfd);
state->sockfd = INVALID_SOCKET;
return "ConnectEx() failed";
}
return NULL;
}
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
{
if (state->sockfd == INVALID_SOCKET)
return "ffNetworkingSendHttpRequest() failed";
uint32_t timeout = state->timeout;
if (timeout > 0)
{
if (WaitForSingleObject((HANDLE) state->sockfd, timeout) != WAIT_OBJECT_0)
{
CancelIo((HANDLE) state->sockfd);
closesocket(state->sockfd);
return "WaitForSingleObject(state->sockfd) failed or timeout";
}
}
DWORD transfer, flags;
if (!WSAGetOverlappedResult(state->sockfd, &state->overlapped, &transfer, TRUE, &flags))
{
closesocket(state->sockfd);
return "WSAGetOverlappedResult() failed";
}
if(timeout > 0)
{
//https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout, sizeof(timeout));
}
uint32_t recvStart;
do {
recvStart = buffer->length;
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, (int) ffStrbufGetFree(buffer), 0);
if (received <= 0) break;
buffer->length = recvStart + (uint32_t) received;
buffer->chars[buffer->length] = '\0';
} while (ffStrbufGetFree(buffer) > 0 && strstr(buffer->chars + recvStart, "\r\n\r\n") == NULL);
closesocket(state->sockfd);
if (buffer->length == 0) return "Empty server response received";
return ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n") ? NULL : "Invalid response";
}
+32 -49
View File
@@ -28,55 +28,6 @@ const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName)
return subKey;
}
bool ffOptionParseModuleArgs(const char* argumentKey, const char* subKey, const char* value, FFModuleArgs* result)
{
if(ffStrEqualsIgnCase(subKey, "key"))
{
ffOptionParseString(argumentKey, value, &result->key);
return true;
}
else if(ffStrEqualsIgnCase(subKey, "format"))
{
ffOptionParseString(argumentKey, value, &result->outputFormat);
return true;
}
else if(ffStrEqualsIgnCase(subKey, "output-color"))
{
if(value == NULL)
{
fprintf(stderr, "Error: usage: %s <str>\n", argumentKey);
exit(477);
}
ffOptionParseColor(value, &result->outputColor);
return true;
}
else if(ffStrStartsWithIgnCase(subKey, "key-"))
{
const char* subKey2 = subKey + strlen("key-");
if(ffStrEqualsIgnCase(subKey2, "color"))
{
if(value == NULL)
{
fprintf(stderr, "Error: usage: %s <str>\n", argumentKey);
exit(477);
}
ffOptionParseColor(value, &result->keyColor);
return true;
}
else if(ffStrEqualsIgnCase(subKey2, "width"))
{
result->keyWidth = ffOptionParseUInt32(argumentKey, value);
return true;
}
else if(ffStrEqualsIgnCase(subKey2, "icon"))
{
ffOptionParseString(argumentKey, value, &result->keyIcon);
return true;
}
}
return false;
}
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer)
{
if(value == NULL)
@@ -157,6 +108,8 @@ bool ffOptionParseBoolean(const char* str)
void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
{
if (!value || value[0] == '\0') return;
// If value is already an ANSI escape code, use it
if (value[0] == '\e' && value[1] == '[')
{
@@ -177,6 +130,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
if (ffCharIsEnglishAlphabet(value[0]))
{
FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET)
else FF_APPEND_COLOR_CODE_COND(bold_, FF_COLOR_MODE_BOLD)
else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD)
else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM)
else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC)
@@ -212,6 +166,35 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
exit(479);
}
}
else if (value[0] == '#')
{
// RGB color
++value;
char* pend = NULL;
uint32_t rgb = (uint32_t) strtoul(value, &pend, 16);
if (pend == value) {
fprintf(stderr, "Error: invalid RGB color code found: %s\n", value);
exit(479);
}
if (pend - value > 6) {
fprintf(stderr, "Error: RGB color code too long: %s\n", value);
exit(479);
}
else if (pend - value == 3) {
rgb = ((rgb & 0xF00) >> 8) * 0x110000 +
((rgb & 0x0F0) >> 4) * 0x001100 +
((rgb & 0x00F) >> 0) * 0x000011;
}
else if (pend - value != 6) {
fprintf(stderr, "Error: invalid RGB color code length: %s\n", value);
exit(479);
}
uint32_t r = rgb >> 16, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
ffStrbufAppendF(buffer, FF_COLOR_FG_RGB "%u;%u;%u", r, g, b);
value = pend;
continue;
}
ffStrbufAppendC(buffer, *value);
++value;
+14 -5
View File
@@ -29,10 +29,12 @@ typedef struct FFModuleBaseInfo
// This is UB, because `void*` is not compatible with `FF*Options*`.
// However we can't do it better unless we move to C++, so that `option` becomes a `this` pointer
// https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type
bool (*parseCommandOptions)(void* options, const char* key, const char* value);
void (*initOptions)(void* options);
void (*destroyOptions)(void* options);
void (*parseJsonObject)(void* options, struct yyjson_val *module);
void (*printModule)(void* options);
void (*generateJsonResult)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* module);
bool (*printModule)(void* options); // true on success
bool (*generateJsonResult)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* module); // true on success
void (*generateJsonConfig)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* obj);
FFModuleFormatArgList formatArgs;
} FFModuleBaseInfo;
@@ -42,7 +44,13 @@ typedef enum __attribute__((__packed__)) FFModuleKeyType
FF_MODULE_KEY_TYPE_NONE = 0,
FF_MODULE_KEY_TYPE_STRING = 1 << 0,
FF_MODULE_KEY_TYPE_ICON = 1 << 1,
FF_MODULE_KEY_TYPE_BOTH = FF_MODULE_KEY_TYPE_STRING | FF_MODULE_KEY_TYPE_ICON,
FF_MODULE_KEY_TYPE_SPACE_SHIFT = 4,
FF_MODULE_KEY_TYPE_BOTH_0 = FF_MODULE_KEY_TYPE_STRING | FF_MODULE_KEY_TYPE_ICON,
FF_MODULE_KEY_TYPE_BOTH_1 = FF_MODULE_KEY_TYPE_BOTH_0 | (1 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
FF_MODULE_KEY_TYPE_BOTH = FF_MODULE_KEY_TYPE_BOTH_1, // alias
FF_MODULE_KEY_TYPE_BOTH_2 = FF_MODULE_KEY_TYPE_BOTH_0 | (2 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
FF_MODULE_KEY_TYPE_BOTH_3 = FF_MODULE_KEY_TYPE_BOTH_0 | (3 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
FF_MODULE_KEY_TYPE_BOTH_4 = FF_MODULE_KEY_TYPE_BOTH_0 | (4 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
FF_MODULE_KEY_TYPE_FORCE_UNSIGNED = UINT8_MAX,
} FFModuleKeyType;
@@ -63,7 +71,6 @@ typedef struct FFKeyValuePair
} FFKeyValuePair;
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName);
bool ffOptionParseModuleArgs(const char* argumentKey, const char* pkey, const char* value, FFModuleArgs* result);
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer);
FF_C_NODISCARD uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value);
FF_C_NODISCARD int32_t ffOptionParseInt32(const char* argumentKey, const char* value);
@@ -94,3 +101,5 @@ static inline void ffOptionDestroyModuleArg(FFModuleArgs* args)
ffStrbufDestroy(&args->outputFormat);
ffStrbufDestroy(&args->outputColor);
}
enum { FF_OPTION_MAX_SIZE = 1 << 8 }; // Maximum size of a single option value, used for static allocation
+9 -94
View File
@@ -2,7 +2,6 @@
#include "common/parsing.h"
#include <ctype.h>
#include <inttypes.h>
#ifdef _WIN32
#pragma GCC diagnostic push
@@ -51,63 +50,21 @@ int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2)
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty)
{
if(version->major > 0 || version->minor > 0 || version->patch > 0)
ffStrbufAppendF(pretty, "%u", version->major);
{
ffStrbufAppendUInt(pretty, version->major);
}
if(version->minor > 0 || version->patch > 0)
ffStrbufAppendF(pretty, ".%u", version->minor);
{
ffStrbufAppendC(pretty, '.');
ffStrbufAppendUInt(pretty, version->minor);
}
if(version->patch > 0)
ffStrbufAppendF(pretty, ".%u", version->patch);
}
static void parseSize(FFstrbuf* result, uint64_t bytes, uint32_t base, const char** prefixes)
{
double size = (double) bytes;
uint8_t counter = 0;
while(size >= base && counter < instance.config.display.sizeMaxPrefix && prefixes[counter + 1])
{
size /= base;
counter++;
ffStrbufAppendC(pretty, '.');
ffStrbufAppendUInt(pretty, version->patch);
}
if(counter == 0)
ffStrbufAppendF(result, "%" PRIu64 " %s", bytes, prefixes[0]);
else
ffStrbufAppendF(result, "%.*f %s", instance.config.display.sizeNdigits, size, prefixes[counter]);
}
void ffParseSize(uint64_t bytes, FFstrbuf* result)
{
switch (instance.config.display.sizeBinaryPrefix)
{
case FF_SIZE_BINARY_PREFIX_TYPE_IEC:
parseSize(result, bytes, 1024, (const char*[]) {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL});
break;
case FF_SIZE_BINARY_PREFIX_TYPE_SI:
parseSize(result, bytes, 1000, (const char*[]) {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL});
break;
case FF_SIZE_BINARY_PREFIX_TYPE_JEDEC:
parseSize(result, bytes, 1024, (const char*[]) {"B", "KB", "MB", "GB", "TB", NULL});
break;
default:
parseSize(result, bytes, 1024, (const char*[]) {"B", NULL});
break;
}
}
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result)
{
if (mhz == 0)
return false;
int8_t ndigits = instance.config.display.freqNdigits;
if (ndigits >= 0)
ffStrbufAppendF(result, "%.*f GHz", ndigits, mhz / 1000.);
else
ffStrbufAppendF(result, "%u MHz", (unsigned) mhz);
return true;
}
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
@@ -190,48 +147,6 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
}
}
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result)
{
if(days == 0 && hours == 0 && minutes == 0)
{
ffStrbufAppendF(result, "%u seconds", seconds);
return;
}
if(days > 0)
{
ffStrbufAppendF(result, "%u day", days);
if(days > 1)
ffStrbufAppendC(result, 's');
if(days >= 100)
ffStrbufAppendS(result, "(!)");
if(hours > 0 || minutes > 0)
ffStrbufAppendS(result, ", ");
}
if(hours > 0)
{
ffStrbufAppendF(result, "%u hour", hours);
if(hours > 1)
ffStrbufAppendC(result, 's');
if(minutes > 0)
ffStrbufAppendS(result, ", ");
}
if(minutes > 0)
{
ffStrbufAppendF(result, "%u min", minutes);
if(minutes > 1)
ffStrbufAppendC(result, 's');
}
}
#ifdef _WIN32
#pragma GCC diagnostic pop
#endif
-4
View File
@@ -24,7 +24,3 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty);
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
void ffParseSize(uint64_t bytes, FFstrbuf* result);
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result);
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result);
+78 -64
View File
@@ -60,23 +60,32 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
const FFOptionsDisplay* options = &instance.config.display;
uint32_t blocksPercent = (uint32_t) (percent / 100.0 * options->barWidth + 0.5);
const bool borderAsValue = options->barBorderLeftElapsed.length && options->barBorderRightElapsed.length;
uint8_t blocksPercent = (uint8_t) (percent / 100.0 * options->barWidth + 0.5);
assert(blocksPercent <= options->barWidth);
if(options->barBorderLeft.length)
if(!borderAsValue && options->barBorderLeft.length)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
if(!options->pipe && options->barColorBorder.length > 0)
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
ffStrbufAppend(buffer, &options->barBorderLeft);
}
if (percent != percent)
if (percent == -DBL_MAX)
{
if(!options->pipe)
// Use total color for simplification
if(!options->pipe && options->barColorTotal.length > 0)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
for (uint32_t i = 0; i < options->barWidth; ++i)
ffStrbufAppend(buffer, &options->barCharElapsed);
for (uint8_t i = 0; i < options->barWidth; ++i)
{
ffStrbufAppend(buffer, borderAsValue && i == 0
? &options->barBorderLeft
: borderAsValue && i == options->barWidth - 1
? &options->barBorderRight
: &options->barCharTotal);
}
}
else
{
@@ -85,61 +94,72 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
const char* colorRed = options->percentColorRed.chars;
FFPercentageTypeFlags percentType = config.type == 0 ? options->percentType : config.type;
bool monochrome = !!(percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT);
for (uint32_t i = 0; i < blocksPercent; ++i)
bool autoColorElapsed = ffStrbufIgnCaseEqualS(&options->barColorElapsed, "auto");
bool monochrome = (percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT) || !autoColorElapsed;
if (!options->pipe && options->barColorElapsed.length > 0 && monochrome)
{
if(!options->pipe)
const char* color = NULL;
if (!autoColorElapsed)
color = options->barColorElapsed.chars;
else if (green <= yellow)
{
if (monochrome)
{
const char* color = NULL;
if (green <= yellow)
{
if (percent < green) color = colorGreen;
else if (percent < yellow) color = colorYellow;
else color = colorRed;
}
else
{
if (percent < yellow) color = colorRed;
else if (percent < green) color = colorYellow;
else color = colorGreen;
}
ffStrbufAppendF(buffer, "\e[%sm", color);
}
else
{
uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
if (i == section2Begin)
ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed));
else if (i == section1Begin)
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
else if (i == 0)
ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed));
}
if (percent < green) color = colorGreen;
else if (percent < yellow) color = colorYellow;
else color = colorRed;
}
ffStrbufAppend(buffer, &options->barCharElapsed);
else
{
if (percent < yellow) color = colorRed;
else if (percent < green) color = colorYellow;
else color = colorGreen;
}
ffStrbufAppendF(buffer, "\e[%sm", color);
}
for (uint8_t i = 0; i < blocksPercent; ++i)
{
if (!options->pipe && options->barColorElapsed.length > 0 && !monochrome)
{
uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
if (i == section2Begin)
ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed));
else if (i == section1Begin)
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
else if (i == 0)
ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed));
}
ffStrbufAppend(buffer, borderAsValue && i == 0
? &options->barBorderLeftElapsed
: borderAsValue && i == options->barWidth - 1
? &options->barBorderRightElapsed
: &options->barCharElapsed);
}
if (blocksPercent < options->barWidth)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
for (uint32_t i = blocksPercent; i < options->barWidth; ++i)
ffStrbufAppend(buffer, &options->barCharTotal);
if(!options->pipe && options->barColorTotal.length > 0)
ffStrbufAppendF(buffer, "\e[%sm", options->barColorTotal.chars);
for (uint8_t i = blocksPercent; i < options->barWidth; ++i)
{
ffStrbufAppend(buffer, borderAsValue && i == 0
? &options->barBorderLeft
: borderAsValue && i == options->barWidth - 1
? &options->barBorderRight
: &options->barCharTotal);
}
}
}
if(options->barBorderRight.length)
if(!borderAsValue && options->barBorderRight.length)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
if(!options->pipe && options->barColorBorder.length > 0)
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
ffStrbufAppend(buffer, &options->barBorderRight);
}
if(!options->pipe)
if(!options->pipe && (options->barColorElapsed.length > 0 || options->barColorTotal.length > 0 || options->barColorBorder.length > 0))
{
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
appendOutputColor(buffer, module);
@@ -165,7 +185,7 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
const char* colorYellow = options->percentColorYellow.chars;
const char* colorRed = options->percentColorRed.chars;
if(percent != percent)
if(percent == -DBL_MAX)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
else if(green <= yellow)
{
@@ -175,7 +195,6 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
else
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
}
else
{
@@ -187,7 +206,8 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
}
}
ffStrbufAppendF(buffer, "%.*f%%", options->percentNdigits, percent);
ffStrbufAppendF(buffer, "%*.*f%s%%", options->percentWidth, options->percentNdigits, percent,
options->percentSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
if (colored && !options->pipe)
{
@@ -239,14 +259,14 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha
return false;
}
bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageModuleConfig* config)
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config)
{
if (!ffStrEqualsIgnCase(key, "percent"))
if (!unsafe_yyjson_equals_str(key, "percent"))
return false;
if (!yyjson_is_obj(value))
{
fprintf(stderr, "Error: usage: %s must be an object\n", key);
fprintf(stderr, "Error: usage: %s must be an object\n", unsafe_yyjson_get_str(key));
exit(480);
}
@@ -288,16 +308,10 @@ bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageMo
return true;
}
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig defaultConfig, FFPercentageModuleConfig config)
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config)
{
if (config.green == defaultConfig.green && config.yellow == defaultConfig.yellow)
return;
yyjson_mut_val* percent = yyjson_mut_obj_add_obj(doc, module, "percent");
if (config.green != defaultConfig.green)
yyjson_mut_obj_add_uint(doc, percent, "green", config.green);
if (config.yellow != defaultConfig.yellow)
yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow);
if (config.type != defaultConfig.type)
yyjson_mut_obj_add_uint(doc, percent, "type", config.type);
yyjson_mut_obj_add_uint(doc, percent, "green", config.green);
yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow);
yyjson_mut_obj_add_uint(doc, percent, "type", config.type);
}
+3 -3
View File
@@ -11,7 +11,7 @@ typedef enum __attribute__((__packed__)) FFPercentageTypeFlags
FF_PERCENTAGE_TYPE_BAR_BIT = 1 << 1,
FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT = 1 << 2,
FF_PERCENTAGE_TYPE_NUM_COLOR_BIT = 1 << 3,
FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT = FF_PERCENTAGE_TYPE_NUM_COLOR_BIT,
FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT = 1 << 4,
FF_PERCENTAGE_TYPE_FORCE_UNSIGNED_ = UINT8_MAX,
} FFPercentageTypeFlags;
static_assert(sizeof(FFPercentageTypeFlags) == 1, "");
@@ -40,6 +40,6 @@ typedef struct yyjson_val yyjson_val;
typedef struct yyjson_mut_doc yyjson_mut_doc;
typedef struct yyjson_mut_val yyjson_mut_val;
bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentageModuleConfig* config);
bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageModuleConfig* config);
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig defaultConfig, FFPercentageModuleConfig config);
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config);
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config);
const char* ffPercentParseTypeJsonConfig(yyjson_val* value, FFPercentageTypeFlags* result);
+12 -15
View File
@@ -1,5 +1,6 @@
#include "fastfetch.h"
#include "common/printing.h"
#include "logo/logo.h"
#include "util/textModifier.h"
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType)
@@ -27,17 +28,12 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
ffPrintColor(&instance.config.display.colorKeys);
}
bool hasIcon = false;
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_ICON && moduleArgs && moduleArgs->keyIcon.length > 0)
{
ffStrbufWriteTo(&moduleArgs->keyIcon, stdout);
hasIcon = true;
}
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_STRING)
{
if(hasIcon)
putchar(' ');
ffPrintCharTimes(' ', instance.config.display.keyType >> FF_MODULE_KEY_TYPE_SPACE_SHIFT);
//NULL check is required for modules with custom keys, e.g. disk with the folder path
if((printType & FF_PRINT_TYPE_NO_CUSTOM_KEY) || !moduleArgs || moduleArgs->key.length == 0)
@@ -99,7 +95,7 @@ void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleAr
ffStrbufPutTo(&buffer, stdout);
}
static void printError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, va_list arguments)
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
{
if(!instance.config.display.showErrors)
return;
@@ -109,7 +105,10 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
if(!instance.config.display.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
va_list arguments;
va_start(arguments, message);
vprintf(message, arguments);
va_end(arguments);
if(!instance.config.display.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
@@ -117,14 +116,6 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
putchar('\n');
}
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
{
va_list arguments;
va_start(arguments, message);
printError(moduleName, moduleIndex, moduleArgs, printType, message, arguments);
va_end(arguments);
}
void ffPrintColor(const FFstrbuf* colorValue)
{
//If the color is not set, this would reset in \033[m, which resets everything.
@@ -140,6 +131,12 @@ void ffPrintCharTimes(char c, uint32_t times)
if(times == 0)
return;
if(times == 1)
{
putchar(c);
return;
}
char str[32];
memset(str, c, sizeof(str)); //2 instructions when compiling with AVX2 enabled
for(uint32_t i = sizeof(str); i <= times; i += (uint32_t)sizeof(str))
+25 -4
View File
@@ -2,13 +2,30 @@
#include "util/FFstrbuf.h"
#include <sys/types.h>
#ifndef _WIN32
#include <sys/types.h> // pid_t
#endif
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr);
typedef struct FFProcessHandle {
#if _WIN32
void* pid; // HANDLE
void* pipeRead; // HANDLE
#else
pid_t pid;
int pipeRead;
#endif
} FFProcessHandle;
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle);
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer); // Destroys handle internally
static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[])
{
const char* error = ffProcessAppendOutput(buffer, argv, false);
FFProcessHandle handle;
const char* error = ffProcessSpawn(argv, false, &handle);
if (error) return error;
error = ffProcessReadOutput(&handle, buffer);
if (!error)
ffStrbufTrimRightSpace(buffer);
return error;
@@ -16,7 +33,11 @@ static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const ar
static inline const char* ffProcessAppendStdErr(FFstrbuf* buffer, char* const argv[])
{
const char* error = ffProcessAppendOutput(buffer, argv, true);
FFProcessHandle handle;
const char* error = ffProcessSpawn(argv, true, &handle);
if (error) return error;
error = ffProcessReadOutput(&handle, buffer);
if (!error)
ffStrbufTrimRightSpace(buffer);
return error;
+192 -41
View File
@@ -12,6 +12,10 @@
#include <errno.h>
#include <sys/wait.h>
#if !(__ANDROID__ || __OpenBSD__)
#include <spawn.h>
#endif
#if defined(__FreeBSD__) || defined(__APPLE__)
#include <sys/types.h>
#include <sys/user.h>
@@ -33,6 +37,10 @@
#include <image.h>
#endif
#ifndef environ
extern char** environ;
#endif
enum { FF_PIPE_BUFSIZ = 8192 };
static inline int ffPipe2(int* fds, int flags)
@@ -48,15 +56,85 @@ static inline int ffPipe2(int* fds, int flags)
#endif
}
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
// Not thread-safe
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle)
{
int pipes[2];
const int timeout = instance.config.general.processingTimeout;
if(ffPipe2(pipes, O_CLOEXEC) == -1)
return "pipe() failed";
pid_t childPid = fork();
pid_t childPid = -1;
int nullFile = ffGetNullFD();
#if !(__ANDROID__ || __OpenBSD__)
// NetBSD / Darwin: native syscall
// Linux (glibc): clone3-execve
// FreeBSD: vfork-execve
// illumos: vforkx-execve
// OpenBSD / Android (bionic): fork-execve
posix_spawn_file_actions_t file_actions;
posix_spawn_file_actions_init(&file_actions);
posix_spawn_file_actions_adddup2(&file_actions, pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
posix_spawn_file_actions_adddup2(&file_actions, nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
static char* oldLang = NULL;
static int langIndex = -1;
if (langIndex >= 0)
{
// Found before
if (oldLang) // oldLang was set only if it needed to be changed
{
if (environ[langIndex] != oldLang)
{
// environ is changed outside of this function
langIndex = -1;
}
else
environ[langIndex] = (char*) "LANG=C.UTF-8";
}
}
if (langIndex < 0)
{
for (int i = 0; environ[i] != NULL; i++)
{
if (ffStrStartsWith(environ[i], "LANG="))
{
langIndex = i;
const char* langValue = environ[i] + 5; // Skip "LANG="
if (ffStrEqualsIgnCase(langValue, "C") ||
ffStrStartsWithIgnCase(environ[i], "C.") ||
ffStrEqualsIgnCase(langValue, "en_US") ||
ffStrStartsWithIgnCase(langValue, "en_US."))
break; // No need to change LANG
oldLang = environ[i];
environ[i] = (char*) "LANG=C.UTF-8"; // Set LANG to C.UTF-8 for consistent output
break;
}
}
}
int ret = posix_spawnp(&childPid, argv[0], &file_actions, NULL, argv, environ);
if (oldLang)
environ[langIndex] = oldLang;
posix_spawn_file_actions_destroy(&file_actions);
if (ret != 0)
{
close(pipes[0]);
close(pipes[1]);
return "posix_spawnp() failed";
}
#else
// https://github.com/termux/termux-packages/issues/25369
childPid = fork();
if(childPid == -1)
{
close(pipes[0]);
@@ -64,49 +142,72 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
return "fork() failed";
}
//Child
if(childPid == 0)
{
int nullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
// Child process
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
setenv("LANG", "C", 1);
putenv("LANG=C.UTF-8");
execvp(argv[0], argv);
_exit(127);
}
//Parent
close(pipes[1]);
#endif
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
close(pipes[1]);
outHandle->pid = childPid;
outHandle->pipeRead = pipes[0];
return NULL;
}
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
{
assert(handle->pipeRead != -1);
assert(handle->pid != -1);
const int32_t timeout = instance.config.general.processingTimeout;
FF_AUTO_CLOSE_FD int childPipeFd = handle->pipeRead;
pid_t childPid = handle->pid;
handle->pipeRead = -1;
handle->pid = -1;
char str[FF_PIPE_BUFSIZ];
while(1)
for (;;)
{
if (timeout >= 0)
{
struct pollfd pollfd = { childPipeFd, POLLIN, 0 };
if (poll(&pollfd, 1, timeout) == 0)
int pollret = poll(&pollfd, 1, timeout);
if (pollret == 0)
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
}
else if (errno == EINTR)
else if (pollret < 0)
{
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
if (waitpid(childPid, NULL, WNOHANG) == childPid)
if (errno == EINTR)
{
// Read remaining data from the pipe
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
childPid = -1;
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
if (waitpid(childPid, NULL, WNOHANG) == childPid)
{
// Read remaining data from the pipe
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
childPid = -1;
}
}
else
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) error: not EINTR";
}
}
else if (pollfd.revents & POLLERR)
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) error";
return "poll(&pollfd, 1, timeout) error: POLLERR";
}
}
@@ -121,7 +222,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if (!WIFEXITED(stat_loc))
return "child process exited abnormally";
if (WEXITSTATUS(stat_loc) == 127)
return "command was not found";
return "command not found";
// We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c`
return NULL;
}
@@ -134,7 +235,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
else
break;
}
};
}
return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed";
}
@@ -144,15 +245,42 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
assert(processName->length > 0);
ffStrbufClear(exe);
#ifdef __linux__
#if defined(__linux__) || defined(__GNU__)
char filePath[64];
snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int)pid);
if(ffReadFileBuffer(filePath, exe))
{
ffStrbufRecalculateLength(exe); //Trim the arguments
ffStrbufTrimRightSpace(exe);
const char* p = exe->chars;
uint32_t len = (uint32_t) strlen(p);
if (len + 1 < exe->length)
{
const char* name = memrchr(p, '/', len);
if (name) name++; else name = p;
// For interpreters, try to find the real script path in the arguments
if (ffStrStartsWith(name, "python")
#ifndef __ANDROID__
|| ffStrEquals(name, "guile") // for shepherd
#endif
)
{
// `cmdline` always ends with a trailing '\0', and ffReadFileBuffer appends another \0
// So `exe->chars` is always double '\0' terminated
for (p = p + len + 1; *p && *p == '-'; p += strlen(p) + 1) // Skip arguments
assert(p - exe->chars < exe->allocated);
if (*p)
{
len = (uint32_t) strlen(p);
memmove(exe->chars, p, len + 1);
}
}
}
assert(len < exe->allocated);
exe->length = len;
ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash
}
@@ -279,8 +407,10 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
psinfo_t proc;
if (ffReadFileData(filePath, sizeof(proc), &proc) == sizeof(proc))
{
ffStrbufSetS(exe, proc.pr_psargs);
ffStrbufSubstrBeforeFirstC(exe, ' ');
const char* args = proc.pr_psargs;
if (args[0] == '-') ++args;
const char* end = strchr(args, ' ');
ffStrbufSetNS(exe, end ? (uint32_t) (end - args) : (uint32_t) strlen(args), args);
}
if (exePath)
@@ -344,33 +474,53 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
if (pid <= 0)
return "Invalid pid";
#ifdef __linux__
#if defined(__linux__) || defined(__GNU__)
char procFilePath[64];
if (ppid)
#if __linux__
if (ppid || tty)
#endif
{
snprintf(procFilePath, sizeof(procFilePath), "/proc/%d/stat", (int)pid);
char buf[PROC_FILE_BUFFSIZ];
ssize_t nRead = ffReadFileData(procFilePath, sizeof(buf) - 1, buf);
if(nRead <= 8)
return "ffReadFileData(/proc/pid/stat, PROC_FILE_BUFFSIZ-1, buf) failed";
buf[nRead] = '\0';
buf[nRead] = '\0'; // pid (comm) state ppid pgrp session tty
*ppid = 0;
static_assert(sizeof(*ppid) == sizeof(int), "");
const char* pState = NULL;
ffStrbufEnsureFixedLengthFree(name, 255);
int tty_;
if(
sscanf(buf, "%*s (%255[^)]) %*c %d %*d %*d %d", name->chars, ppid, &tty_) < 2 || //stat (comm) state ppid pgrp session tty
name->chars[0] == '\0'
)
return "sscanf(stat) failed";
{
// comm in `/proc/pid/stat` is not encoded, and may contain ' ', ')' or even `\n`
const char* start = memchr(buf, '(', (size_t) nRead);
if (!start)
return "memchr(stat, '(') failed";
start++;
const char* end = memrchr(start, ')', (size_t) nRead - (size_t) (start - buf));
if (!end)
return "memrchr(stat, ')') failed";
ffStrbufSetNS(name, (uint32_t) (end - start), start);
ffStrbufTrimRightSpace(name);
if (name->chars[0] == '\0')
return "process name is empty";
pState = end + 2; // skip ") "
}
ffStrbufRecalculateLength(name);
if (tty)
*tty = tty_ & 0xFF;
#if !__linux__
if (ppid || tty)
#endif
{
int ppid_, tty_;
if(sscanf(pState + 2, "%d %*d %*d %d", &ppid_, &tty_) < 2)
return "sscanf(stat) failed";
if (ppid)
*ppid = (pid_t) ppid_;
if (tty)
*tty = tty_ & 0xFF;
}
}
#if __linux__
else
{
snprintf(procFilePath, sizeof(procFilePath), "/proc/%d/comm", (int)pid);
@@ -379,6 +529,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
return "ffReadFileBuffer(/proc/pid/comm, name) failed";
ffStrbufTrimRightSpace(name);
}
#endif
#elif defined(__APPLE__)
+76 -38
View File
@@ -2,7 +2,7 @@
#include "common/processing.h"
#include "common/io/io.h"
#include <Windows.h>
#include <windows.h>
#include <ntstatus.h>
#include <winternl.h>
@@ -45,12 +45,13 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result)
}
}
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle)
{
int timeout = instance.config.general.processingTimeout;
const int32_t timeout = instance.config.general.processingTimeout;
wchar_t pipeName[32];
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u", GetCurrentProcessId());
static unsigned pidCounter = 0;
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", GetCurrentProcessId(), ++pidCounter);
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = CreateNamedPipeW(
pipeName,
@@ -81,47 +82,68 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if (hChildPipeWrite == INVALID_HANDLE_VALUE)
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
PROCESS_INFORMATION piProcInfo = {0};
BOOL success;
PROCESS_INFORMATION piProcInfo = {};
STARTUPINFOA siStartInfo = {
.cb = sizeof(siStartInfo),
.dwFlags = STARTF_USESTDHANDLES,
};
if (useStdErr)
{
STARTUPINFOA siStartInfo = {
.cb = sizeof(siStartInfo),
.dwFlags = STARTF_USESTDHANDLES,
};
if (useStdErr)
siStartInfo.hStdError = hChildPipeWrite;
else
siStartInfo.hStdOutput = hChildPipeWrite;
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
argvToCmdline(argv, &cmdline);
success = CreateProcessA(
NULL, // application name
cmdline.chars, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
);
siStartInfo.hStdOutput = ffGetNullFD();
siStartInfo.hStdError = hChildPipeWrite;
}
else
{
siStartInfo.hStdOutput = hChildPipeWrite;
siStartInfo.hStdError = ffGetNullFD();
}
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
argvToCmdline(argv, &cmdline);
BOOL success = CreateProcessA(
NULL, // application name
cmdline.chars, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
);
CloseHandle(hChildPipeWrite);
if(!success)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
return "command not found";
return "CreateProcessA() failed";
}
FF_AUTO_CLOSE_FD HANDLE hProcess = piProcInfo.hProcess;
FF_MAYBE_UNUSED FF_AUTO_CLOSE_FD HANDLE hThread = piProcInfo.hThread;
CloseHandle(piProcInfo.hThread); // we don't need the thread handle
outHandle->pid = piProcInfo.hProcess;
outHandle->pipeRead = hChildPipeRead;
hChildPipeRead = INVALID_HANDLE_VALUE; // ownership transferred, don't close it
return NULL;
}
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
{
assert(handle->pipeRead != INVALID_HANDLE_VALUE);
assert(handle->pid != INVALID_HANDLE_VALUE);
int32_t timeout = instance.config.general.processingTimeout;
FF_AUTO_CLOSE_FD HANDLE hProcess = handle->pid;
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = handle->pipeRead;
handle->pid = INVALID_HANDLE_VALUE;
handle->pipeRead = INVALID_HANDLE_VALUE;
char str[FF_PIPE_BUFSIZ];
DWORD nRead = 0;
OVERLAPPED overlapped = { };
OVERLAPPED overlapped = {};
// ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED
do
{
@@ -130,7 +152,11 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
switch (GetLastError())
{
case ERROR_IO_PENDING:
if (!timeout || WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
#if __aarch64__
if (!GetOverlappedResultEx(hChildPipeRead, &overlapped, &nRead, timeout < 0 ? INFINITE : (DWORD) timeout, FALSE))
#else
// To support Windows 7
if (timeout >= 0 && WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
{
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
@@ -138,18 +164,23 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
}
if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE))
#endif
{
if (GetLastError() == ERROR_BROKEN_PIPE)
return NULL;
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
return "GetOverlappedResult(hChildPipeRead) failed";
return "GetOverlappedResult"
#if __aarch64__
"Ex"
#endif
"(hChildPipeRead) failed";
}
break;
case ERROR_BROKEN_PIPE:
return NULL;
goto exit;
default:
CancelIo(hChildPipeRead);
@@ -160,6 +191,13 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
ffStrbufAppendNS(buffer, nRead, str);
} while (nRead > 0);
exit:
{
DWORD exitCode = 0;
if (GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE && exitCode != 0)
return "Child process exited with an error";
}
return NULL;
}
+126 -52
View File
@@ -184,7 +184,7 @@ FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type)
}
#endif //FF_HAVE_DCONF
FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type)
FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type)
{
FFvariant gsettings = ffSettingsGetGSettings(gsettingsSchemaName, gsettingsPath, gsettingsKey, type);
@@ -196,77 +196,151 @@ FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, c
return ffSettingsGetDConf(dconfKey, type);
}
#ifdef FF_HAVE_XFCONF
#include <xfconf/xfconf.h>
typedef struct XFConfData
{
FF_LIBRARY_SYMBOL(xfconf_channel_get)
FF_LIBRARY_SYMBOL(xfconf_channel_has_property)
FF_LIBRARY_SYMBOL(xfconf_channel_get_string)
FF_LIBRARY_SYMBOL(xfconf_channel_get_bool)
FF_LIBRARY_SYMBOL(xfconf_channel_get_int)
FF_LIBRARY_SYMBOL(xfconf_init)
bool inited;
} XFConfData;
static const XFConfData* getXFConfData(void)
{
static XFConfData data;
if (!data.inited)
{
data.inited = true;
FF_LIBRARY_LOAD(libxfconf, NULL, "libxfconf-0" FF_LIBRARY_EXTENSION, 4);
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_has_property, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_string, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_bool, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_int, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_init, NULL)
if(!data.ffxfconf_init(NULL))
data.ffxfconf_init = NULL;
else
libxfconf = NULL;
}
if(!data.ffxfconf_init)
return NULL;
return &data;
}
#ifdef FF_HAVE_DBUS
#include "common/dbus.h"
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
{
const XFConfData* data = getXFConfData();
if(data == NULL)
FFDBusData dbus;
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
return FF_VARIANT_NULL;
XfconfChannel* channel = data->ffxfconf_channel_get(channelName); // Never fails according to documentation but rather returns an empty channel
if(!data->ffxfconf_channel_has_property(channel, propertyName))
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetProperty", channelName, propertyName);
if(!reply)
return FF_VARIANT_NULL;
DBusMessageIter rootIterator;
if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator))
{
dbus.lib->ffdbus_message_unref(reply);
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_INT)
return (FFvariant) {.intValue = data->ffxfconf_channel_get_int(channel, propertyName, 0)};
{
int32_t value;
if (ffDBusGetInt(&dbus, &rootIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .intValue = value };
}
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_STRING)
return (FFvariant) {.strValue = data->ffxfconf_channel_get_string(channel, propertyName, NULL)};
{
FFstrbuf value = ffStrbufCreate();
if (ffDBusGetString(&dbus, &rootIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
}
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_BOOL)
return (FFvariant) {.boolValue = data->ffxfconf_channel_get_bool(channel, propertyName, false), .boolValueSet = true};
{
bool value;
if (ffDBusGetBool(&dbus, &rootIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .boolValue = value, .boolValueSet = true };
}
}
return FF_VARIANT_NULL;
}
#else //FF_HAVE_XFCONF
#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \
{ \
if(!(dbus).lib->ffdbus_message_iter_next(iterator)) \
break; \
continue; \
}
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
{
FFDBusData dbus;
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
return FF_VARIANT_NULL;
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetAllProperties", channelName, propertyPrefix);
if(!reply)
return FF_VARIANT_NULL;
DBusMessageIter rootIterator;
if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator))
{
dbus.lib->ffdbus_message_unref(reply);
return FF_VARIANT_NULL;
}
DBusMessageIter arrayIterator;
dbus.lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator);
while(true)
{
if(dbus.lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY)
FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
DBusMessageIter dictIterator;
dbus.lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator);
const char* key;
dbus.lib->ffdbus_message_iter_get_basic(&dictIterator, &key);
if (cb(data, key)) FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
dbus.lib->ffdbus_message_iter_next(&dictIterator);
if(type == FF_VARIANT_TYPE_INT)
{
int32_t value;
if (ffDBusGetInt(&dbus, &dictIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .intValue = value };
}
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_STRING)
{
FFstrbuf value = ffStrbufCreate();
if (ffDBusGetString(&dbus, &dictIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
}
return FF_VARIANT_NULL;
}
if(type == FF_VARIANT_TYPE_BOOL)
{
bool value;
if (ffDBusGetBool(&dbus, &dictIterator, &value))
{
dbus.lib->ffdbus_message_unref(reply);
return (FFvariant) { .boolValue = value, .boolValueSet = true };
}
}
return FF_VARIANT_NULL;
}
return FF_VARIANT_NULL;
}
#else //FF_HAVE_DBUS
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
{
FF_UNUSED(channelName, propertyName, type)
return FF_VARIANT_NULL;
}
#endif //FF_HAVE_XFCONF
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
{
FF_UNUSED(channelName, propertyPrefix, type, data, cb);
return FF_VARIANT_NULL;
}
#endif //FF_HAVE_DBUS
#ifdef FF_HAVE_SQLITE3
#include <sqlite3.h>
+3 -1
View File
@@ -24,8 +24,10 @@ typedef union FFvariant
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type);
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type);
FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type);
FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type);
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type);
typedef bool FFTestXfconfPropCallback(void* data, const char* propertyName); // Return false to break loop
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb);
int ffSettingsGetSQLite3Int(const char* dbPath, const char* query);
bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result);
+44
View File
@@ -0,0 +1,44 @@
#include "size.h"
#include <inttypes.h>
static void appendNum(FFstrbuf* result, uint64_t bytes, uint32_t base, const char** prefixes)
{
const FFOptionsDisplay* options = &instance.config.display;
double size = (double) bytes;
uint8_t counter = 0;
while(size >= base && counter < options->sizeMaxPrefix && prefixes[counter + 1])
{
size /= base;
counter++;
}
if (counter == 0)
ffStrbufAppendUInt(result, bytes);
else
ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits, true);
if (options->sizeSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER)
ffStrbufAppendC(result, ' ');
ffStrbufAppendS(result, prefixes[counter]);
}
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result)
{
const FFOptionsDisplay* options = &instance.config.display;
switch (options->sizeBinaryPrefix)
{
case FF_SIZE_BINARY_PREFIX_TYPE_IEC:
appendNum(result, bytes, 1024, (const char*[]) {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL});
break;
case FF_SIZE_BINARY_PREFIX_TYPE_SI:
appendNum(result, bytes, 1000, (const char*[]) {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL});
break;
case FF_SIZE_BINARY_PREFIX_TYPE_JEDEC:
appendNum(result, bytes, 1024, (const char*[]) {"B", "KB", "MB", "GB", "TB", NULL});
break;
default:
appendNum(result, bytes, 1024, (const char*[]) {"B", NULL});
break;
}
}
+3
View File
@@ -0,0 +1,3 @@
#include "fastfetch.h"
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result);
+15 -21
View File
@@ -5,7 +5,7 @@
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module)
{
if (celsius != celsius) // ignores NaN
if (celsius == -DBL_MAX) // ignores invalid value
return;
const FFOptionsDisplay* options = &instance.config.display;
@@ -41,13 +41,16 @@ void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig confi
{
case FF_TEMPERATURE_UNIT_DEFAULT:
case FF_TEMPERATURE_UNIT_CELSIUS:
ffStrbufAppendF(buffer, "%.*f°C", options->tempNdigits, celsius);
ffStrbufAppendF(buffer, "%.*f%s°C", options->tempNdigits, celsius,
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
break;
case FF_TEMPERATURE_UNIT_FAHRENHEIT:
ffStrbufAppendF(buffer, "%.*f°F", options->tempNdigits, celsius * 1.8 + 32);
ffStrbufAppendF(buffer, "%.*f%s°F", options->tempNdigits, celsius * 1.8 + 32,
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
break;
case FF_TEMPERATURE_UNIT_KELVIN:
ffStrbufAppendF(buffer, "%.*f K", options->tempNdigits, celsius + 273.15);
ffStrbufAppendF(buffer, "%.*f%sK", options->tempNdigits, celsius + 273.15,
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ");
break;
}
@@ -104,9 +107,9 @@ bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char*
return false;
}
bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config)
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config)
{
if (!ffStrEqualsIgnCase(key, "temp"))
if (!unsafe_yyjson_equals_str(key, "temp"))
return false;
if (yyjson_is_bool(value))
@@ -123,7 +126,7 @@ bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, F
if (!yyjson_is_obj(value))
{
fprintf(stderr, "Error: usage: %s must be an object or a boolean\n", key);
fprintf(stderr, "Error: usage: %s must be an object or a boolean\n", unsafe_yyjson_get_str(key));
exit(480);
}
@@ -156,23 +159,14 @@ bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, F
return true;
}
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FF_MAYBE_UNUSED bool defaultTemp, FFColorRangeConfig defaultConfig, bool temp, FFColorRangeConfig config)
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config)
{
assert(defaultTemp == false); // assume defaultTemp is always false
if (!temp)
return;
if (config.green != defaultConfig.green || config.yellow != defaultConfig.yellow)
{
yyjson_mut_val* temp = yyjson_mut_obj_add_obj(doc, module, "temp");
if (config.green != defaultConfig.green)
yyjson_mut_obj_add_uint(doc, temp, "green", config.green);
if (config.yellow != defaultConfig.yellow)
yyjson_mut_obj_add_uint(doc, temp, "yellow", config.yellow);
}
yyjson_mut_obj_add_bool(doc, module, "temp", false);
else
{
yyjson_mut_obj_add_bool(doc, module, "temp", true);
yyjson_mut_val* temp = yyjson_mut_obj_add_obj(doc, module, "temp");
yyjson_mut_obj_add_uint(doc, temp, "green", config.green);
yyjson_mut_obj_add_uint(doc, temp, "yellow", config.yellow);
}
}
+2 -2
View File
@@ -5,5 +5,5 @@
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module);
bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* value, bool* useTemp, FFColorRangeConfig* config);
bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config);
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FF_MAYBE_UNUSED bool defaultTemp, FFColorRangeConfig defaultConfig, bool temp, FFColorRangeConfig config);
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config);
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config);
+2 -2
View File
@@ -65,8 +65,8 @@
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
{
ts.tv_sec += ts.tv_sec / 1000;
ts.tv_nsec += (ts.tv_nsec % 1000) * 1000000;
ts.tv_sec += timeout / 1000;
ts.tv_nsec += (timeout % 1000) * 1000000;
if (pthread_timedjoin_np(thread, NULL, &ts) != 0)
{
pthread_kill(thread, SIGTERM);
+3
View File
@@ -0,0 +1,3 @@
#include <time.h>
char ffTimeInternalBuffer[64]; // Reduce memory usage and prevent redundant allocations
+67 -8
View File
@@ -11,6 +11,8 @@
#include <OS.h>
#endif
#include "util/arrayUtils.h"
static inline double ffTimeGetTick(void) //In msec
{
#ifdef _WIN32
@@ -64,11 +66,12 @@ static inline const char* ffTimeToFullStr(uint64_t msec)
time_t tsec = (time_t) (msec / 1000);
const struct tm* tm = localtime(&tsec);
static char buf[32];
strftime(buf, __builtin_strlen("0000-00-00T00:00:00") + 1, "%FT%T", tm);
snprintf(buf + __builtin_strlen("0000-00-00T00:00:00"), __builtin_strlen(".000") + 1, ".%03u", (unsigned) (msec % 1000));
strftime(buf + __builtin_strlen("0000-00-00T00:00:00.000"), __builtin_strlen("+0000") + 1, "%z", tm);
return buf;
extern char ffTimeInternalBuffer[64];
uint32_t len = 0;
len += (uint32_t) strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer) - len, "%FT%T", tm);
len += (uint32_t) snprintf(ffTimeInternalBuffer + len, ARRAY_SIZE(ffTimeInternalBuffer) - len, ".%03u", (unsigned) (msec % 1000));
len += (uint32_t) strftime(ffTimeInternalBuffer + len, ARRAY_SIZE(ffTimeInternalBuffer) - len, "%z", tm);
return ffTimeInternalBuffer;
}
// Not thread-safe
@@ -77,11 +80,67 @@ static inline const char* ffTimeToShortStr(uint64_t msec)
if (msec == 0) return "";
time_t tsec = (time_t) (msec / 1000);
static char buf[32];
strftime(buf, sizeof(buf), "%F %T", localtime(&tsec));
return buf;
extern char ffTimeInternalBuffer[64];
strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer), "%F %T", localtime(&tsec));
return ffTimeInternalBuffer;
}
// Not thread-safe
static inline const char* ffTimeToTimeStr(uint64_t msec)
{
if (msec == 0) return "";
time_t tsec = (time_t) (msec / 1000);
extern char ffTimeInternalBuffer[64];
uint32_t len = (uint32_t) strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer), "%T", localtime(&tsec));
sprintf(ffTimeInternalBuffer + len, ".%03u", (unsigned) (msec % 1000));
return ffTimeInternalBuffer;
}
#ifdef _WIN32
#pragma GCC diagnostic pop
#endif
typedef struct FFTimeGetAgeResult
{
uint32_t years;
uint32_t daysOfYear;
double yearsFraction;
} FFTimeGetAgeResult;
static inline FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs)
{
FFTimeGetAgeResult result = {};
if (__builtin_expect(birthMs == 0 || nowMs < birthMs, 0))
return result;
time_t birth_s = (time_t) (birthMs / 1000);
struct tm birth_tm;
#ifdef _WIN32
localtime_s(&birth_tm, &birth_s);
#else
localtime_r(&birth_s, &birth_tm);
#endif
time_t now_s = (time_t) (nowMs / 1000);
struct tm now_tm;
#ifdef _WIN32
localtime_s(&now_tm, &now_s);
#else
localtime_r(&now_s, &now_tm);
#endif
result.years = (uint32_t) (now_tm.tm_year - birth_tm.tm_year);
if (now_tm.tm_yday < birth_tm.tm_yday)
result.years--;
birth_tm.tm_year += (int) result.years;
birth_s = mktime(&birth_tm);
uint32_t diff_s = (uint32_t) (now_s - birth_s);
result.daysOfYear = diff_s / (24 * 60 * 60);
birth_tm.tm_year += 1;
result.yearsFraction = (double) diff_s / (double) (mktime(&birth_tm) - birth_s) + result.years;
return result;
}
+241 -940
View File
File diff suppressed because it is too large Load Diff
-24
View File
@@ -1,24 +0,0 @@
Usage: fastfetch --color <color>
Shortcut of `fastfetch --color-keys <color> --color-title <color>`.
If no color is set, the main color of the logo will be used.
Following information applies to all settings
<color> must be a color encoding as ANSI escape sequences. It is inserted between "ESC[" and "m".
Infos about them can be found here: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters.
Examples:
35: sets the color to magenta
38;5;38: sets the color to 38th color of ANSI 256 colors
4;92: sets the color to bright green with underline
5;104: blinking text on a blue background
ANSI named colors are also supported:
magenta: equivalent to `35`
underline_bright_green: equivalent to `4;92`
After v2.15.0, some special keys can be used:
keys: use the color set by `--color-keys`
title: use the color set by `--color-title`
output: use the color set by `--color-output`
separator: use the color set by `--color-separator`
-4
View File
@@ -1,4 +0,0 @@
Parsing is not case sensitive. E.g. "--lib-PCI" is equal to "--Lib-Pci"
If a value starts with a ?, it is optional. An optional boolean value defaults to true if not specified.
More detailed help messages for each options can be printed with "-h <option_without_dash_prefix>"
All options can be made permanent with command "fastfetch <options> --gen-config"
-55
View File
@@ -1,55 +0,0 @@
A format string is a string that contains placeholders for values.
These placeholders begin with a '{', containing the index of the value, and end with a '}'.
For example the format string "Values: {1} ({2})", with the values "First" and "My second val", will produce "Values: First (My second val)".
The format string can contain placeholders in any order and have multiple occurrences.
To include spaces when setting from the command line, surround the whole string with double quotes (").
In 2.14.0 or newer, the value indices can be meaningful named tags.
For example: "--title-format '{user-name-colored}{at-symbol-colored}{host-name-colored}'" is equivalent to "--title-format '{6}{7}{8}'"
See "fastfetch -h title-format" for all supported tags.
In 2.17.0 or newer, a truncation length can be specified using syntax '<arg>:<trunc-length>`
For example: "--title-format '{user-name:5}'" will truncate user name into 5-length string.
If '<trunc-length>' is negative, an ellipsis … will be appended at the end when the original string is truncated.
Note: The string length is counted in raw bytes. Multi-byte unicode characters and ANSI escape codes are not taken into account.
In 2.23.0 or newer, `<` or `>` can be specified instead of `:` to set a left or right padding.
For example: "--title-format '{user-name<20}'" will generate `<user-name> `;
"--title-format '{user-name>20}'" will generate ` <user-name>`
In 2.24.0 or newer, `{~startIndex,endIndex}` can be specified to slice a string. Negative index counts back from the end of the string.
If an index is omitted, 0 is used. For example, both `{~,0}` `{~0,}` and `{~,}` are same as `{~0,0}` and will always generate a empty string.
If `,endIndex` is omitted or greater than the length of the string, the length of string is used.
In 2.36.0 or newer, `{$NUM}` can be specified to reference a constant defined in `display.constants`. `{$ENV_VAR}` can be specified to reference an environment variable.
If the value index is missing, meaning the placeholder is "{}", an internal counter sets the value index.
This means that the format string "Values: {1} ({2})" is equivalent to "Values: {} ({})".
Note that this counter only counts empty placeholders, so the format string "{2} {} {}" will contain the second value, then the first, and then the second again.
To make formatting easier, a double open curly brace ("{{") will be printed as a single open curly brace and not counted as the beginning of a placeholder.
If a value index is misformatted or wants a non-existing value, it will be printed as is, with the curly braces around it.
If the last placeholder isn't closed, it will be treated like it was at the end of the format string.
To only print something if a variable is set, use "{?<index>} ... {?}".
For example, to only print a second value if it is set, use "{?2} Second value: {2}{?}".
If a "{?}" is found without an opener, it is printed as is.
To only print something if a variable is not set, do the same as with if, just replace every '?' with a '/'.
For example to print a fallback for a second value if it is not set, use "{?2}{2}{?}{/2}Second value fallback{/}".
To stop formatting at any point in the format string, use "{-}".
To print something with color, start a placeholder with a '#' and then the linux terminal color encoding.
"\033[" at the start, and an 'm' at the end is automatically added, so don't do that.
A "{#}" is equivalent to a "{#0}" and resets everything to normal.
For example to print something pink and underline, use "{#4;35}...{#}". "{#underline_magenta}" is also supported. See `fastfetch -h color` for detail.
Information about what the numbers mean can be found here: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters.
Which escape codes are supported and how they look is defined by your terminal.
If a format string evaluates to an empty value, the whole line in the output will be discarded.
You can therefore use --host-format " " to disable host output.
Note that --host-format "" would evaluate as not set, and therefore use the built-in host format
Format string is also the way to go to set a fixed value - just use one without placeholders.
For example when running in headless mode, you could use "--display-format Preferred".
+3 -2
View File
@@ -1,8 +1,9 @@
#pragma once
#include "fastfetch.h"
#include "modules/battery/option.h"
#define FF_BATTERY_TEMP_UNSET (0/0.0)
#define FF_BATTERY_TEMP_UNSET (-DBL_MAX)
typedef struct FFBatteryResult
{
@@ -15,7 +16,7 @@ typedef struct FFBatteryResult
double capacity;
double temperature;
uint32_t cycleCount;
int32_t timeRemaining;
int32_t timeRemaining; // in seconds, -1 if unknown
} FFBatteryResult;
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results);
+8 -3
View File
@@ -96,6 +96,7 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
battery->temperature = FF_BATTERY_TEMP_UNSET;
battery->cycleCount = 0;
battery->timeRemaining = -1;
battery->capacity = 0;
ffStrbufInit(&battery->manufacturer);
ffStrbufInit(&battery->modelName);
ffStrbufInit(&battery->status);
@@ -124,11 +125,11 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
{
double level = 0, scale = 0;
if (ffParsePropLines(start, "level: ", &temp))
level = ffStrbufToDouble(&temp);
level = ffStrbufToDouble(&temp, -DBL_MAX);
ffStrbufClear(&temp);
if (ffParsePropLines(start, "scale: ", &temp))
scale = ffStrbufToDouble(&temp);
scale = ffStrbufToDouble(&temp, -DBL_MAX);
ffStrbufClear(&temp);
if (level > 0 && scale > 0)
@@ -138,7 +139,11 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
if(options->temp)
{
if (ffParsePropLines(start, "temperature: ", &temp))
battery->temperature = ffStrbufToDouble(&temp);
{
battery->temperature = ffStrbufToDouble(&temp, FF_BATTERY_TEMP_UNSET);
if (battery->temperature != FF_BATTERY_TEMP_UNSET)
battery->temperature /= 10.0; // Android returns temperature in tenths of a degree
}
ffStrbufClear(&temp);
}

Some files were not shown because too many files have changed in this diff Show More