Compare commits

...

355 Commits

Author SHA1 Message Date
Carter Li aa3a916d5a Merge pull request #2183 from fastfetch-cli/dev
Release: v2.59.0
2026-02-14 00:15:11 +08:00
Carter Li 6e64b758bf Chore: silences a compiler warning 2026-02-13 23:37:40 +08:00
李通洲 49ef7fc51f Packages (Windows): code cleanups 2026-02-13 20:50:45 +08:00
李通洲 0e9a5acdbd Platform (Windows): adds init / destroy of field sid 2026-02-13 20:42:35 +08:00
李通洲 4f6e80e940 Release: v2.59.0 2026-02-13 19:39:33 +08:00
李通洲 df87cdfa6e Windows: defines NtCurrentProcess and uses it 2026-02-13 19:38:22 +08:00
李通洲 dee4b36a46 Bluetooth (Windows): use modern dlls 2026-02-13 19:25:06 +08:00
李通洲 d04a26337a Swap (Windows): removes unused code 2026-02-13 19:25:06 +08:00
Dark Knightz 2afe8d11d1 Common: fixes discarded-qualifiers warnings (#2181) 2026-02-13 18:05:07 +08:00
李通洲 f31d3b8b21 Doc: update changelog 2026-02-13 10:04:54 +08:00
李通洲 8a20af9917 Doc: update JSON schema 2026-02-13 10:02:28 +08:00
李通洲 fc5c2f6213 Title: adds {user-id} in custom format 2026-02-13 09:38:22 +08:00
Carter Li 6c314e148a Logo (Builtin): updates nixos_small too
Ref #2180
2026-02-13 09:09:05 +08:00
Konnor Klercke a86d0017a9 Logo (Builtin): adds 6-color support to nixos logo (#2180)
Co-authored-by: Konnor Klercke <kklercke@brite.com>
2026-02-13 08:58:48 +08:00
李通洲 4038ed2656 GPU: adds debug logs
Thanks Github Copilot
2026-02-12 18:56:42 +08:00
李通洲 0f4bb47c2f Global: fixes compiler warnings 2026-02-12 16:25:33 +08:00
李通洲 19f7c67ede Platform: adds pid field and use it 2026-02-12 14:29:49 +08:00
李通洲 ff7e81ed81 Memory (Windows): adds comments [ci skip] 2026-02-11 21:47:20 +08:00
李通洲 681a102a2b Processing (Windows): adds TODO [ci skip] 2026-02-11 21:47:09 +08:00
李通洲 ba27f4f2ef CI: adds Solaris 2026-02-11 15:50:58 +08:00
李通洲 cbe33a4860 CI (DragonFly): disables packaging .pkg file to fix a weird CI error 2026-02-11 15:50:58 +08:00
李通洲 5847e3f269 FFPlatform (Windows): fixes memory corruption 2026-02-11 10:03:29 +08:00
李通洲 b248dfa01c Platform: prefers system API to retreive user name 2026-02-10 23:42:57 +08:00
李通洲 357aa77e21 Media (Solaris): fixes another compiling error
Fixes #2173
2026-02-10 22:42:36 +08:00
李通洲 a44bde6f94 Platform: adds UID / SID detection 2026-02-10 20:33:28 +08:00
李通洲 5825bce57d Disk (Windows): replaces most Kernel32 calls to ntdll calls
* Improves accurancy of detection of drive create time
* Improves performance slightly
* Removes remove drive check, `hideFolders` should be used instead
2026-02-10 18:50:35 +08:00
李通洲 996cdd3155 Refactor: moves memrchr to global impl for potential future use 2026-02-10 18:16:58 +08:00
李通洲 61cdfcabf8 Windows: uses SHGetKnownFolderPath instead of the unreliable getenv 2026-02-10 17:32:34 +08:00
李通洲 359a77097c Terminal (Windows): uses NtQueryInformationProcess to retrieve information of conhost.exe 2026-02-10 17:32:34 +08:00
李通洲 1323d007d3 Global: uses alignas where applicable 2026-02-10 17:32:34 +08:00
李通洲 d2215f26ac Processing (Windows): uses NtQueryInformationProcess instead of its wrapper 2026-02-10 17:32:34 +08:00
李通洲 958e7dbd8f Bluetooth (Windows): simplifies code 2026-02-10 17:32:34 +08:00
Verdgil 5b10cde59f Global: Add support for Oracle Solaris (#2176)
* Fix Oracle Solaris zpool build

* Add memrchr fallback

* Change to include fron extern

* add new line

* remove ; in zpool.c

* Change wrapper to macro

Also change README.md

* Tweaks

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-02-10 17:32:20 +08:00
李通洲 e8f2b9a1c7 Common: uses _Countof in ARRAY_SIZE definition when available 2026-02-02 11:08:26 +08:00
Carter Li 0686d1db4a GPU (Hurd): uses native API; removes libpciaccess dep 2026-01-30 20:34:47 +08:00
李通洲 7c284f9ee8 CMake (macOS): disable ENABLE_APPLE_MEMSIZE_USABLE by default 2026-01-29 13:11:48 +08:00
李通洲 dc04273bd7 Memory (macOS): updates algorithm in order not to use hw.memsize_usable which is available on newer macOS version
Adds a new CMake option to use usable memory size at the same time

Fixes #2171
2026-01-29 09:34:50 +08:00
李通洲 d698be6239 CPU (ARM): removes duplicated cases 2026-01-27 14:48:05 +08:00
李通洲 e44df27c96 Memory (macOS): adds debug info
Usage: `fastfetch -s memory:swap -l none --dynamic-interval 1000 --debug --no-buffer`
See https://github.com/fastfetch-cli/fastfetch/issues/2171#issuecomment-3803309478
2026-01-27 14:24:38 +08:00
李通洲 b365d4cca1 CPU (ARM): adds more ARM parts 2026-01-26 10:17:28 +08:00
李通洲 19d3c948ad DE (Android): clarifies that Google Pixel and other OSes also report ro.build.display.id 2026-01-26 10:17:28 +08:00
李通洲 4a581039d5 CI: fixes building 2026-01-24 09:17:13 +08:00
李通洲 79849fb2b5 CI: updates dependencies 2026-01-23 10:26:04 +08:00
李通洲 c116a5abdf Chore: uses elvis operators where applicatable 2026-01-22 15:36:42 +08:00
Carter Li 8f082730a8 Packaging: update debian stuff [ci skip] 2026-01-22 15:35:44 +08:00
Carter Li b81c4a04db Merge pull request #2164 from fastfetch-cli/dev
Release: v2.58.0
2026-01-21 15:03:51 +08:00
李通洲 e26a05e3ac DE (Linux): ensures process returns successfully before using its output 2026-01-21 14:28:40 +08:00
李通洲 f08a1fb0b4 Release: v2.58.0 2026-01-21 14:12:53 +08:00
李通洲 2a82009ffe WM (macOS): checks the version of WindowServer instead of WindowManager 2026-01-21 09:39:31 +08:00
李通洲 e851f3a7ed Packages (Linux): optimises pacman detection code 2026-01-20 10:06:02 +08:00
Sean Will 3a865df09e Packages (Linux): Auto detect the DBPath directory for pacman on archlinux (#2154)
Fixes #2068
2026-01-19 19:44:30 -06:00
berezka bae80e2932 Add new KISS Linux logo based off favicon 2026-01-20 09:42:28 +08:00
berezka 4445e1e78d Fix Bedrock Linux version detection & futureproof for 0.8 2026-01-20 09:42:28 +08:00
Carter Li f0e3d3d8e1 Host (Linux): uses /sys/firmware/devicetree/base/smbios if available 2026-01-20 09:20:48 +08:00
Carter Li a313fd1572 Linux: uses the standard /sys/firmware/devicetree/base instead of the outdated /proc/device-tree 2026-01-20 09:11:47 +08:00
Carter Li 927d44d919 Chassis (Linux): uses /proc/device-tree/smbios if available 2026-01-20 08:59:22 +08:00
Carter Li 3b9a91e8af DE (Linux): silences compiler warnings [ci skip] 2026-01-20 08:34:46 +08:00
李通洲 70b4582bb6 DE (Linux): removes option slowVersionDetection
It's always true now

Fixes #2149
2026-01-19 10:55:30 +08:00
李通洲 461552b8d0 DynamicInterval: reruns prepare code before next interval
Fixes #2152
2026-01-16 20:02:03 +08:00
Carter Li 0f3db37199 Chassis (Linux): supports arm devices 2026-01-16 16:47:51 +08:00
Carter Li 67f16b269a DisplayServer (Linux): regenerates wlr-output-management-unstable-v1*
NOOP
2026-01-16 10:40:53 +08:00
李通洲 25671fa4b4 DisplayServer (Linux): fixes crashes on KDE beta
Fixes #2150
2026-01-16 10:13:50 +08:00
Kirill Rekhov 4eaa04d4a4 Presets: update examples to replace deprecated --load-config with --config 2026-01-16 00:43:03 +08:00
李通洲 7592885b9f GPU (Windows): ensures devId is uppercase for consistent parsing 2026-01-15 15:46:21 +08:00
李通洲 508a3fde36 Windows: fixes building 2026-01-15 15:43:05 +08:00
李通洲 f0273224e0 JsonSchema: update [ci skip] 2026-01-15 15:24:54 +08:00
李通洲 31e833c02e Colors: updates module description
Fixes #2147
2026-01-15 15:20:38 +08:00
李通洲 a20d915412 JsonConfig: supports --structure-disabled 2026-01-15 15:11:08 +08:00
李通洲 d3453de73c Global: puts more fastfetch-only properties into FFdata 2026-01-15 15:06:23 +08:00
李通洲 79a11c4728 CommandOption: adds a new option --structure-disabled (WIP)
To disable modules temporarily
2026-01-15 10:35:21 +08:00
李通洲 24591417ce FFstrbuf: clarify usage requirements for ffStrbufGetdelim and friends 2026-01-15 10:30:40 +08:00
李通洲 de6d066fc9 LICENSE: update copyright year to 2026 [ci skip] 2026-01-14 16:33:51 +08:00
Carter Li 6362c896f8 Packaging: updates debian stuff [ci skip] 2026-01-14 14:10:46 +08:00
Carter Li 0418e9ca5e Merge pull request #2145 from fastfetch-cli/dev
Release: v2.57.1
2026-01-13 23:58:22 -06:00
李通洲 ba0eeab18c DisplayServer (Linux): cleanup code 2026-01-14 13:47:40 +08:00
李通洲 5ef630cbc8 Release: v2.57.1 2026-01-14 13:20:55 +08:00
李通洲 1699d14984 Common: ensures thread safety of ffTimeInitQpcMultiplier 2026-01-14 10:03:51 +08:00
Carter Li 501746a270 Logo: removes unneeded #includes
Fixes #2143
2026-01-14 08:50:56 +08:00
李通洲 e6bd1c340f Common: add on_scope_exit utility for scope-based resource management 2026-01-13 18:33:02 +08:00
李通洲 49fc95689d Platform (Windows): improves hostname retrieval by adding fallback to NetBIOS name 2026-01-13 10:44:52 +08:00
李通洲 3d84ad19be macOS: uses MACH_PORT_NULL to maintain compatibility with older SDKs
Fixes #2140
2026-01-13 10:12:31 +08:00
Rain Xelelo 57aa0cf499 Logo (Builtin): updates PrismLinux and adds a small variant (#2141)
* Add files via upload

* Update builtin.c

* Update builtin.c

* Update builtin.c

* PrismLinux logo update + small variant

* Update ASCII art in prismlinux.txt

* Revise ASCII art in prismlinux_small.txt

Updated ASCII art in prismlinux_small.txt

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-01-13 10:04:38 +08:00
Carter Li 6496dcd7d0 DisplayServer (Linux): refactors property handling in xcb and xlib 2026-01-13 09:24:27 +08:00
李通洲 1c066bc69a Common: updates ffTimeSleep to return true on success 2026-01-12 15:16:03 +08:00
李通洲 2f1e37bb7c Common (Windows): improves performance of ffTimeGetTick 2026-01-12 15:16:02 +08:00
李通洲 fd3c87abe7 Github: adds pull_request_template.md [ci skip] 2026-01-12 11:04:04 +08:00
李通洲 af075b8ef8 Github: update logo_request.yml [ci skip] 2026-01-12 11:04:04 +08:00
Carter Li 71d461266e Packaging: updates debian stuff [ci skip] 2026-01-12 10:19:39 +08:00
Carter Li 163781557f Merge pull request #2134 from fastfetch-cli/dev
Release: v2.57.0
2026-01-11 20:02:57 -06:00
Carter Li 16e6decebf Logo: general fixes
1. updates JSON schema
2. removes unused fields
3. runs tests in CI
2026-01-12 09:34:25 +08:00
Carter Li e10c9cc164 Doc: updates changelog 2026-01-12 09:06:43 +08:00
Carter Li 7ef994d0cf Logo (Builtin): update macOS variants 2026-01-12 09:00:57 +08:00
ctb unit 248 019c9f0f77 Logo (Builtin): macOS large Apple logo: add missing warm band using ANSI LIGHT_RED (#2138)
Co-authored-by: ctb248 <ctb248@pm.me>
2026-01-10 09:44:27 +08:00
李通洲 5fec607ebe Doc: updates changelog 2026-01-09 20:14:00 +08:00
李通洲 b065b3da51 Global: optimises usage of FFstrbuf and FFlist 2026-01-09 20:14:00 +08:00
李通洲 1337525eb5 Shell: fixes xonsh version detection 2026-01-09 20:14:00 +08:00
李通洲 30ea52938e Processing (SunOS): tidy 2026-01-09 20:14:00 +08:00
李通洲 d43ed33661 Shell (macOS): fixes exePath not reports absolute paths 2026-01-09 20:14:00 +08:00
李通洲 03aab33507 Shell (Linux): supports version detection for deleted binaries
Fixes #2136
2026-01-09 20:14:00 +08:00
李通洲 420d1cf804 FFstrbuf: updates ffStrbufSet* that they won't reserve extra space 2026-01-09 20:13:59 +08:00
Ezozbek 5d901da81b Logo (Builtin): adds Xinux logo (#2135)
* Logo (Builtin): adds Xinux logo

* Fix formatting in xinux.txt ASCII art

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-01-08 18:57:28 -06:00
李通洲 5c783e64c0 Logo: adds new module for querying raw builtin logo data
Fixes #2124
2026-01-08 16:39:52 +08:00
李通洲 2efa5a1869 Logo: code refactor for future use 2026-01-08 15:56:44 +08:00
李通洲 5bfabe7a52 Presets: adds a new example 2026-01-08 14:13:19 +08:00
李通洲 c9c9a58f59 Colors: supports @<color-index> 2026-01-08 14:10:47 +08:00
李通洲 546908fc29 Release: v2.57.0 2026-01-08 10:02:31 +08:00
李通洲 0a17da2da0 CI (Windows): build win7-compat artifacts 2026-01-08 09:40:11 +08:00
李通洲 bc6fd025cb Common: silences compiler warnings 2026-01-07 20:11:41 +08:00
李通洲 9e49451340 Display (Windows): supports dpi scale factor detection on Win 7 2026-01-07 20:04:54 +08:00
李通洲 4d185e64ac SunOS: silences compiler warnings 2026-01-07 18:38:44 +08:00
李通洲 1fa9a61b3f CMake (Windows): fixes option ENABLE_WIN7_COMPAT 2026-01-07 18:32:58 +08:00
李通洲 234552fbf2 CI (OpenBSD): uses clang-21 2026-01-07 16:22:28 +08:00
李通洲 8423efb686 CMake (Windows): introduces a flag to remove Win7 compat mode 2026-01-07 11:05:12 +08:00
李通洲 cd8c15d01e OS (Windows): acquires OS name from registry 2026-01-07 10:36:28 +08:00
李通洲 3163cfb1b6 Common (Windows): improves performance a littile 2026-01-07 10:35:48 +08:00
李通洲 7ae007a1d0 CI (OpenBSD): upgrades OS version 2026-01-07 08:58:20 +08:00
李通洲 0b52d75415 GPU (Windows): assumes Win10+ on WoA 2026-01-07 08:58:03 +08:00
李通洲 3a7f4f5848 Uptime (Windows): silences a compiler warning 2026-01-07 08:56:00 +08:00
李通洲 072f67988f Networking: prefers WSA* functions
No functional change.
2026-01-06 22:57:27 +08:00
李通洲 c640ddbff7 Uptime (Windows): uses QueryInterruptTime on WoA unconditionally 2026-01-06 22:41:00 +08:00
李通洲 981ae6bdd1 GPU: improves error handling and add case-insensitive PCI ID parsing 2026-01-06 20:21:03 +08:00
李通洲 977e3f317e Uptime (Windows): improves accurancy on Windows 10 and later 2026-01-06 19:59:02 +08:00
Carter Li e2ee24598c Zpool: add "Is read-only" option to module info 2026-01-06 18:49:52 +08:00
李通洲 1be90084ab Networking: fixes some issues and memory leaks 2026-01-06 16:44:36 +08:00
李通洲 6ded0f9bb0 CMake: fixes building 2026-01-06 10:25:41 +08:00
Carter Li d60b25e424 Refactor: renames src/util to src/common 2026-01-06 09:48:38 +08:00
Carter Li 874f3918b7 Util: moves util/*.c to util/impl/ 2026-01-06 09:42:54 +08:00
Carter Li 61690a1804 Util: moves util/io/io.h to util/io.h 2026-01-06 09:13:40 +08:00
李通洲 1e43e35857 Chore: merges common/* into util/* 2026-01-05 17:54:41 +08:00
李通洲 8c86003220 Common: introduces FF_LIBRARY_LOAD_MESSAGE to simplify library-loading 2026-01-05 17:54:41 +08:00
Carter Li 18c3cd2e66 CPU (Linux): fixes speed detection on s390x
Fixes #2129
2026-01-05 10:50:55 +08:00
Carter Li b21f35e914 CMake (Hurd): defines O_PATH=0 2026-01-05 10:45:19 +08:00
李通洲 32e3ed1fda SMC: optimises code 2026-01-04 16:45:02 +08:00
李通洲 6f87026b0c Host (macOS): uses IORegistryEntryFromPath if applicatable 2026-01-04 15:38:25 +08:00
李通洲 e23edae917 Board (macOS): removes an unused #include 2026-01-04 15:37:11 +08:00
Carter Li bdc867031a TerminalFont (Linux): check xterm.vt100.faceName for xterm font detection 2026-01-04 10:41:24 +08:00
李通洲 e96b0f7a73 Netif (Linux): skips local/loopback routes
Fixes #2127
2026-01-01 23:35:14 +08:00
Carter Li 37fe446a58 TerminalFont (Linux): supports cosmic-term 2026-01-01 22:52:03 +08:00
Carter Li f03a0bc202 Terminal (Linux): supports cosmic-term version detection 2026-01-01 22:32:32 +08:00
Carter Li bcbc5a4bff DE (Linux): fix COSMIC version detection 2026-01-01 22:29:11 +08:00
qaqland 0b1e2faba1 Logo (Builtin): fix colors of UOS 2025-12-31 08:03:19 +08:00
qaqland 4708a5e59c Logo (Builtin): fix colors of deepin 2025-12-31 08:03:19 +08:00
Carter Li 7925469e2f DE (Linux): detect COSMIC version 2025-12-28 23:16:58 +08:00
Carter Li 53116d65f1 WM (Linux): supports niri version detection
Fixes #2121
2025-12-28 23:16:45 +08:00
李通洲 01917b781b Bootmgr (macOS): supports secure boot detection on Intel 2025-12-27 18:12:23 +08:00
李通洲 d01fc56ea2 Bootmgr (macOS): supports secure boot detection 2025-12-27 16:11:16 +08:00
李通洲 9c870a57f0 PhysicalMemory (macOS): improves performance on Apple Silicon 2025-12-27 15:58:56 +08:00
3ventic 7e557a06b3 JsonSchema: correct references for keyboard, mouse items (#2119) [ci skip] 2025-12-27 10:15:04 +08:00
Joe_ fa63038862 Logo (Builtin): renames HydraPWK to NetHydra 2025-12-26 20:38:12 +08:00
Carter Li 8439204cef DisplayServer (Linux): upgrades kde-output-device-v2 wayland protocol files (again) 2025-12-23 16:17:01 +08:00
李通洲 710df0b87b TerminalFont (Linux): improves rxvt detection
Ref #2105
2025-12-23 16:03:04 +08:00
李通洲 302f0fc85f TerminalFont (Linux): supports urxvt
Fixes #2105
2025-12-23 11:05:54 +08:00
Carter Li 241aa3a02c GPU (Linux): silences a strict-aliasing warning
Fixes #2106
2025-12-22 10:28:56 +08:00
李通洲 a17f3dc3f8 Util: fixes building on DragonFly BSD 2025-12-22 08:44:00 +08:00
李通洲 34c0bf58cb Logo (Builtin): adds Tumbleweed braille logo 2025-12-21 18:07:07 +08:00
Carter Li b64b93fc4a Util (mallocHelper): implements ffMallocUsableSize and uses it 2025-12-20 09:26:37 +08:00
Carter Li a9f43ff466 Packaging: update debian stuff 2025-12-18 15:00:51 +08:00
Carter Li 924d78d3c4 Release: v2.56.1 (#2097)
* Logo (Builtin): drop opak

Ref: #1070

* Swap (Windows): adds `K32GetPerformanceInfo` fallback

* Platform (Windows): fixes if checks

* Platform (Windows): adds a null check

* Packages (Windows): improves performance for directory enumeration

* Util (Windows): fixes / adds a new Unicode conversion function

* Packaging: update debian stuff [ci skip]

* IO (Windows): enhances `openat`

* CPU: adds option `tempSensor`

* CPU (macOS): supports `tempSensor`

* CPU (Windows): supports `tempSensor`

* CPU (Linux): supports `tempSensor`

* CPU (FreeBSD): supports `tempSensor`

* CPU (NetBSD): supports `tempSensor`

* CPU (OpenBSD): supports `tempSensor`

* CPU (Linux): prevents variables from integer overflow

* GPU (Linux): add comments

* CPU (SunOS): supports `tempSensor`

* Doc: clarifies that we supports illumos only

* JsonSchema: documents `cpu.tempSensor`

Fixes #2073

* CPUCache (macOS): fixes cache line size detection

* CPU(Linux): Fix build on GNU.

* Chore: refines usage of `PATH_MAX`

* DisplayServer (Linux): upgrades kde-output-device-v2 wayland protocol files (again)

Fixes #2093

* Logo (Builtin): adds gxde logo (#2094)

* add gxde-logo

* add gxdeos

* add gxdeos

* add gxdeos

* Release: v2.56.1

* Memory (macOS): uses `hw.memsize_usable`

* Chore (Windows): Standardize windows header casing. (#2096) [ci skip]

Followup to 0b6ca158ea.

Co-authored-by: Dariqq <dariqq@noreply.codeberg.org>

* IO (Windows): removes unneeded null terminator appending

* CPU (SunOS): adds `const` for consistancy

* Host (macOS): prefers `hw.product` than `hw.model`

... because `HW_MODEL` is deprecated

* Doc: update changelog

* Memory (macOS): Refines Memory usage detection on macOS to match Activity Monitor more closely

* Packages (Windows): fixes possible UB

Reported by Github Copilot

* JsonSchema: refines comments [ci skip]

---------

Co-authored-by: Yelninei <yelninei@tutamail.com>
Co-authored-by: gitee-zeqi <a202128502@163.com>
Co-authored-by: Dariqq <77271900+Dariqq@users.noreply.github.com>
Co-authored-by: Dariqq <dariqq@noreply.codeberg.org>
2025-12-18 14:46:24 +08:00
李通洲 fa92bb84ae JsonSchema: refines comments [ci skip] 2025-12-18 14:35:21 +08:00
李通洲 288d25e17c Packages (Windows): fixes possible UB
Reported by Github Copilot
2025-12-18 14:21:55 +08:00
李通洲 610fc2ea36 Memory (macOS): Refines Memory usage detection on macOS to match Activity Monitor more closely 2025-12-18 13:36:38 +08:00
李通洲 716c0e2b5c Doc: update changelog 2025-12-18 10:00:05 +08:00
李通洲 945aed7160 Host (macOS): prefers hw.product than hw.model
... because `HW_MODEL` is deprecated
2025-12-18 10:00:05 +08:00
李通洲 1d4d68f6e0 CPU (SunOS): adds const for consistancy 2025-12-17 14:30:07 +08:00
李通洲 3e1167260d IO (Windows): removes unneeded null terminator appending 2025-12-17 14:30:07 +08:00
Dariqq 0130f610e9 Chore (Windows): Standardize windows header casing. (#2096) [ci skip]
Followup to 0b6ca158ea.

Co-authored-by: Dariqq <dariqq@noreply.codeberg.org>
2025-12-16 18:53:26 -06:00
李通洲 94941daf4f Memory (macOS): uses hw.memsize_usable 2025-12-16 10:41:27 +08:00
李通洲 2bbd723321 Release: v2.56.1 2025-12-16 10:16:36 +08:00
gitee-zeqi 608382109c Logo (Builtin): adds gxde logo (#2094)
* add gxde-logo

* add gxdeos

* add gxdeos

* add gxdeos
2025-12-15 13:30:47 +08:00
李通洲 bdc5174f68 DisplayServer (Linux): upgrades kde-output-device-v2 wayland protocol files (again)
Fixes #2093
2025-12-15 13:25:26 +08:00
李通洲 bc869f1be9 Chore: refines usage of PATH_MAX 2025-12-12 09:03:18 +08:00
Yelninei dc69e44829 CPU(Linux): Fix build on GNU. 2025-12-11 21:32:45 +08:00
李通洲 d236850119 CPUCache (macOS): fixes cache line size detection 2025-12-11 14:38:06 +08:00
李通洲 60ec8c9097 JsonSchema: documents cpu.tempSensor
Fixes #2073
2025-12-11 14:37:28 +08:00
李通洲 42e7a7d2f7 Doc: clarifies that we supports illumos only 2025-12-11 14:28:12 +08:00
李通洲 e766809e3a CPU (SunOS): supports tempSensor 2025-12-11 14:24:07 +08:00
Carter Li cb1f0300b9 GPU (Linux): add comments 2025-12-11 09:52:50 +08:00
Carter Li f2a29309f3 CPU (Linux): prevents variables from integer overflow 2025-12-11 09:52:50 +08:00
李通洲 6e7b4bab75 CPU (OpenBSD): supports tempSensor 2025-12-11 09:52:50 +08:00
李通洲 b4f39e251c CPU (NetBSD): supports tempSensor 2025-12-11 09:52:50 +08:00
李通洲 af6196fe6e CPU (FreeBSD): supports tempSensor 2025-12-11 09:52:50 +08:00
Carter Li bca56b2049 CPU (Linux): supports tempSensor 2025-12-11 09:52:50 +08:00
李通洲 f4401f172e CPU (Windows): supports tempSensor 2025-12-11 09:52:50 +08:00
李通洲 c11b88fee5 CPU (macOS): supports tempSensor 2025-12-11 09:52:50 +08:00
李通洲 88b1b558d7 CPU: adds option tempSensor 2025-12-11 09:52:50 +08:00
李通洲 ba6cdc77c9 IO (Windows): enhances openat 2025-12-11 09:52:50 +08:00
Carter Li b952772902 Packaging: update debian stuff [ci skip] 2025-12-11 09:52:50 +08:00
李通洲 7a322154fa Util (Windows): fixes / adds a new Unicode conversion function 2025-12-08 20:11:14 +08:00
李通洲 0b6ca158ea Packages (Windows): improves performance for directory enumeration 2025-12-08 16:42:14 +08:00
李通洲 100cd9a72b Platform (Windows): adds a null check 2025-12-08 09:49:54 +08:00
李通洲 98fb810f1f Platform (Windows): fixes if checks 2025-12-08 09:49:54 +08:00
李通洲 c613e558fd Swap (Windows): adds K32GetPerformanceInfo fallback 2025-12-08 09:49:41 +08:00
Carter Li c324f83826 Logo (Builtin): drop opak
Ref: #1070
2025-12-08 09:03:28 +08:00
Carter Li e50421a6ce Merge pull request #2083 from fastfetch-cli/dev
Release: v2.56.0
2025-12-05 22:42:51 +08:00
李通洲 417b944e1c Doc: updates changelog 2025-12-05 21:12:11 +08:00
李通洲 cb8b4b335d FFstrbuf: removes an unnecessary return 2025-12-05 21:10:19 +08:00
李通洲 c0160537b0 Zpool: fixes inconsistant CMake variables 2025-12-05 21:09:00 +08:00
李通洲 4cb7a6424a Logo (Builtin): tidy 2025-12-05 21:08:28 +08:00
李通洲 7d6c79d73e Doc: documents -c - 2025-12-05 10:41:18 +08:00
李通洲 8652737f64 Fastfetch: enhances config file loading with support for config directory
Fixes #2080
2025-12-05 10:32:42 +08:00
李通洲 d6ac89ea8d Release: v2.56.0 2025-12-04 16:15:20 +08:00
李通洲 2b620cf487 CI (SunOS): fixes a CI error 2025-12-04 16:15:20 +08:00
李通洲 f644df481c CPU: exposes numa node count in custom format 2025-12-04 15:21:27 +08:00
李通洲 e99ecacb52 Chore: adds ffIsValidNativeFD and uses it 2025-12-03 09:26:32 +08:00
李通洲 3e22dd4b0e Chore: uses _WIN32 always 2025-12-03 09:26:32 +08:00
Noa Himesaka 19f30ec687 Logo (Builtin): updates Codex Linux new logo (#2071)
* fix: Codex Linux new logo

reMarkable changed their logo so reflecting that change here too

* Modify ASCII art in codex.txt

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-12-03 09:09:07 +08:00
Alxhr0 76bee78200 Chore: fixes comment for AerynOS in builtin.c (#2078) 2025-12-03 09:00:09 +08:00
李通洲 ce7455d8f0 Zpool: allows disabling module 2025-12-01 17:20:50 +08:00
李通洲 5e27ee0f57 Shell: fixes ksh version detection on Linux 2025-12-01 10:04:40 +08:00
全てずんだもんの所爲です 84a5c6ebe8 Packages (Linux): add kiss packages count (#2072) 2025-11-30 19:10:07 -06:00
李通洲 ad7e23f64c TerminalFont: supports the newest Alacritty config format
Fixes #2070
2025-11-28 16:35:14 +08:00
李通洲 2738f20eea GPU (Linux): detect driver specific info for zhaoxin 2025-11-28 03:06:23 +00:00
李通洲 09362b236c Util (Windows): fixes compiling 2025-11-25 19:10:43 +08:00
Carter Li 3cfef81877 Users (Linux): always report the newest session info 2025-11-25 19:04:36 +08:00
Carter Li 3a04ae2542 Users (Linux): adds systemd fallback for user detection on Linux
Fixes #2064
2025-11-25 16:40:52 +08:00
Carter Li dbaf8a319d FFstrbuf: adds ffStrbufGetdelim(Restore) 2025-11-25 15:08:42 +08:00
Carter Li 2fe2a21bfe Terminal: reports sshd if $SSH_TTY is not available 2025-11-25 14:33:35 +08:00
Carter Li 37639c3582 Utils: inlines ffIsAbsolutePath 2025-11-25 14:33:35 +08:00
李通洲 9a74e6d7bc Users (Linux): adds missing endutxent 2025-11-25 14:32:36 +08:00
Carter Li 5d13389827 TerminalShell: uses absolute path when detecting version if available
Closes #2067
2025-11-25 09:10:30 +08:00
李通洲 1c2c6644d5 DE: adds Android OEM UI detection
Ref #1900
2025-11-24 15:17:52 +08:00
李通洲 ffcddf30e3 Logo: improve builtin logo printing for piping and buffering
Fixes #2065
2025-11-24 14:18:45 +08:00
李通洲 22c92c7b05 Doc: recommand Ubuntu PPA [ci skip] 2025-11-21 15:56:43 +08:00
李通洲 b569048010 CMake (SunOS): remove static link of libzfs 2025-11-21 15:56:43 +08:00
李通洲 f703d9ac89 Zpool: simplifies implementation by dropping platform-specific code 2025-11-20 18:18:25 +08:00
Steve Gilissen ed6abfd626 Logo (Builtin): adds OS/2 Warp logo (#2062)
* Add OS2 Warp logo

* Update ASCII art in os2warp.txt

* Refactor OS/2 Warp logo names for consistency

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-11-19 20:16:19 -06:00
李通洲 50388efc78 Zpool: uses runtime lookup for zpool properties to ensure portability
Fixes #2051
2025-11-19 20:26:18 +08:00
李通洲 7e8fb0fa14 Zpool: simplifies impl; exposes allocated/guid/readOnly 2025-11-19 19:27:19 +08:00
Steve Gilissen 9d70469665 Logo (Builtin): adds Amiga logo (#2061)
* Add Amiga logo

* Update ASCII art in amiga.txt

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2025-11-17 19:52:07 -06:00
李通洲 a94f0efb5b CPU: adds NUMA node detection 2025-11-18 09:30:47 +08:00
Carter Li da3a9be7c6 Packaging: update debian stuff [ci skip] 2025-11-18 09:11:54 +08:00
李通洲 cd8ab8e55a Command: Adds splitLines option 2025-11-17 11:01:32 +08:00
李通洲 1b5b32afad GPU (macOS): fixes a comment [ci skip] 2025-11-17 08:59:39 +08:00
Carter Li 917f784438 Merge pull request #2060 from fastfetch-cli/dev
Release: v2.55.1
2025-11-16 09:56:42 +08:00
李通洲 c2d5d5cca1 Release: v2.55.1 2025-11-16 09:29:24 +08:00
Carter Li b435738c34 CMake (macOS): corrects rpath addition for dlopen builds 2025-11-16 09:15:11 +08:00
apocelipes 934905e63a GPU: silence unused parameter warnings 2025-11-16 08:28:28 +08:00
apocelipes d15bb8a232 Display: fix an uninitialized FFDisplayOptions field 2025-11-15 22:34:33 +08:00
李通洲 c22bca1f87 Processing (Linux): blocks SIGCHLD and simplify poll error handling
Partially reverts e9ab67b380

Fixes #2056 & unfixes #1418
2025-11-15 19:34:13 +08:00
Carter Li e04cc9c9d5 Packaging: update debian changelog [ci skip] 2025-11-12 09:24:50 +08:00
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
533 changed files with 7804 additions and 3402 deletions
+3
View File
@@ -0,0 +1,3 @@
github: LinusDierheimer
ko_fi: carterli
custom: https://paypal.me/zhangsongcui
+18 -9
View File
@@ -6,33 +6,42 @@ body:
- type: markdown
attributes:
value: |
Tip: A logo can be displayed by fastfetch without getting into fastfetch's official repo.
For highly customized logo for personal use, it's recommended to keep it locally.
Tip: You can display a logo in fastfetch without adding it to fastfetch's official repo.
For highly customized, personal logos, we recommend keeping them locally.
Please refer to https://github.com/fastfetch-cli/fastfetch/wiki/Migrate-Neofetch-Logo-To-Fastfetch
- type: textarea
attributes:
label: OS
description: Paste content of `/etc/os-release` and `/etc/lsb-release` here. If none of these files exist, describe a way to identify the distro
description: Paste the contents of `/etc/os-release` and `/etc/lsb-release` here. If neither file exists, describe how to identify the distro.
placeholder: cat /etc/os-release
validations:
required: true
- type: input
attributes:
label: Distro Website
description: To help prevent spam and verify the request, a distro website is required, and a downloadable ISO must be available on that site.
placeholder: https://example.com
validations:
required: true
- type: textarea
attributes:
label: ASCII Art
description: An ASCII logo should not take up too much space (smaller than 50x20 characters). Please also include the color codes if not available in `os-release`
description: The ASCII logo should not take up too much space (smaller than 50x20 characters, W x H). Please also include the color codes if they are not available in `os-release`.
placeholder: Paste ASCII art here
validations:
required: true
- type: input
attributes:
label: Original Image
description: If the ASCII art is based on an image, please provide a link to the original image
placeholder: Image URL or distro website URL
label: Original Image URL
description: If the ASCII art is based on an image, please provide a link to the original image file.
placeholder: Image URL from the distro website mentioned above
- type: checkboxes
attributes:
label: Checklist
options:
- label: The ASCII art is smaller than 50x20 characters (width x height)
- label: The ASCII art is smaller than 50x20 characters (W x H).
required: true
- label: The ASCII art contains color codes, or the color codes are available in `os-release`
- label: The ASCII art includes color codes, or the color codes are available in `os-release`.
required: true
- label: The ASCII art has no internal padding (spaces at the start and/or end of lines).
required: true
+26
View File
@@ -0,0 +1,26 @@
## Summary
<!-- Briefly describe what this PR does. -->
## Related issue (required for new logos for new distros)
<!--
If this PR adds a new logo, it MUST be linked to an existing "Logo Request" issue and has the requests fulfilled.
Use one of the following formats so GitHub links it properly:
- Closes #1234
- Fixes #1234
- Resolves #1234
PRs that add logos without an associated Logo Request issue will not be accepted.
-->
Closes #
## Changes
-
## Checklist
- [ ] I have tested my changes locally.
+213 -65
View File
@@ -13,7 +13,7 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install codespell
shell: bash
@@ -32,7 +32,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: uname -a
run: uname -a
@@ -78,7 +78,7 @@ jobs:
ffversion: ${{ steps.ffversion.outputs.ffversion }}
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: uname -a
run: uname -a
@@ -89,8 +89,11 @@ 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 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
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: |
@@ -99,19 +102,19 @@ jobs:
- name: Initialize CodeQL
if: matrix.arch == 'amd64'
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: c
- name: configure project
run: 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 .
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
uses: github/codeql-action/analyze@v4
- name: list features
run: ./fastfetch --list-features
@@ -142,14 +145,83 @@ jobs:
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
cpack
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
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
linux-i686:
name: Linux-i686
runs-on: ubuntu-22.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v6
- name: uname -a
run: uname -a
- name: cat /etc/os-release
run: cat /etc/os-release
- 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 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: 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
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: ldd fastfetch
- name: run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-i686
path: ./fastfetch-*.*
linux-armv7l:
name: Linux-armv7l
runs-on: ubuntu-24.04
@@ -158,7 +230,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: uraimo/run-on-arch-action@v3
@@ -169,12 +241,13 @@ jobs:
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y ca-certificates gpg curl
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 g++ 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 -DCMAKE_INSTALL_PREFIX=/usr .
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
@@ -184,7 +257,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-armv7l
path: ./fastfetch-*.*
@@ -197,7 +270,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: uraimo/run-on-arch-action@v3
@@ -209,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 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 -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
@@ -220,7 +293,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-armv6l
path: ./fastfetch-*.*
@@ -239,19 +312,21 @@ jobs:
- arch: s390x
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: ${{ matrix.arch }}
distro: ubuntu20.04
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 libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-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
@@ -261,7 +336,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
@@ -270,7 +345,7 @@ jobs:
name: Musl-amd64
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: setup alpine linux
uses: jirutka/setup-alpine@master
@@ -299,7 +374,7 @@ jobs:
shell: alpine.sh {0}
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
@@ -319,7 +394,7 @@ jobs:
runs-on: macos-latest
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: uname -a
run: uname -a
@@ -353,17 +428,17 @@ jobs:
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-macos-${{ matrix.arch }}
path: ./fastfetch-*.*
sunos-amd64:
omnios-amd64:
runs-on: ubuntu-latest
name: SunOS-amd64
name: OmniOS-amd64
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: vmactions/omnios-vm@v1
@@ -371,25 +446,60 @@ jobs:
usesh: true
prepare: |
uname -a
pkg install pkg:/package/pkg
pkg update --accept
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja
run: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
cmake --build . --target package --verbose -j4
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja .
cmake --build . --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
cpack
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-omnios-amd64")' >> CPackConfig.cmake
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-sunos-amd64
name: fastfetch-omnios-amd64
path: ./fastfetch-*.*
solaris-amd64:
runs-on: ubuntu-latest
name: Solaris-amd64
steps:
- name: checkout repository
uses: actions/checkout@v6
- name: run VM
uses: vmactions/solaris-vm@v1
with:
usesh: true
release: "11.4-gcc-14"
prepare: |
uname -a
pkg install cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja dconf mesa
run: |
export PKG_CONFIG_PATH=/usr/lib/64/pkgconfig
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja .
cmake --build . --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
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-solaris-amd64")' >> CPackConfig.cmake
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v6
with:
name: fastfetch-solaris-amd64
path: ./fastfetch-*.*
freebsd-amd64:
@@ -400,7 +510,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: cross-platform-actions/action@master
@@ -409,7 +519,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '14.3'
version: '15.0'
run: |
uname -a
sudo pkg update
@@ -424,7 +534,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-freebsd-amd64
path: ./fastfetch-*.*
@@ -437,7 +547,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: cross-platform-actions/action@master
@@ -446,11 +556,12 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '7.7'
version: '7.8'
run: |
uname -a
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
sudo pkg_add -u
sudo pkg_add -r llvm-21.1.2p0 cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
CC=clang-21 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
@@ -460,7 +571,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-openbsd-amd64
path: ./fastfetch-*.*
@@ -473,7 +584,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: cross-platform-actions/action@master
@@ -485,8 +596,8 @@ jobs:
version: '10.1'
run: |
uname -a
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
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
@@ -496,7 +607,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-netbsd-amd64
path: ./fastfetch-*.*
@@ -509,7 +620,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: vmactions/dragonflybsd-vm@v1
@@ -518,10 +629,10 @@ jobs:
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 egl opencl ocl-icd v4l_compat chafa libelf
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: |
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
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
@@ -531,7 +642,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-dragonfly-amd64
path: ./fastfetch-*.*
@@ -544,7 +655,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: cross-platform-actions/action@master
@@ -566,13 +677,13 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: fastfetch-haiku-amd64
path: ./fastfetch-*.*
windows-hosts:
name: Windows-${{ matrix.arch }}
name: Windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
runs-on: ${{ matrix.runs-on }}
permissions:
security-events: write
@@ -585,17 +696,28 @@ jobs:
msystem: CLANG64
msystem-lower: clang64
msys-arch: x86_64
win7-compat-flag: OFF
win7-compat-postfix: ""
- arch: amd64
runs-on: windows-latest
msystem: CLANG64
msystem-lower: clang64
msys-arch: x86_64
win7-compat-flag: ON
win7-compat-postfix: "-win7"
- arch: aarch64
runs-on: windows-11-arm
msystem: CLANGARM64
msystem-lower: clangarm64
msys-arch: aarch64
win7-compat-flag: OFF
win7-compat-postfix: ""
defaults:
run:
shell: msys2 {0}
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: setup-msys2
uses: msys2/setup-msys2@v2
@@ -608,7 +730,7 @@ jobs:
run: uname -a
- name: configure project
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/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 -DENABLE_WIN7_COMPAT=${{ matrix.win7-compat-flag }} .
- name: build project
run: cmake --build . --verbose -j4
@@ -634,17 +756,41 @@ jobs:
- name: run tests
run: ctest --output-on-failure
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
id: upload-unsigned-artifact
name: upload artifacts for signing
uses: actions/upload-artifact@v6
with:
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
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
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.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
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
uses: actions/upload-artifact@v4
- name: upload true artifacts
uses: actions/upload-artifact@v6
with:
name: fastfetch-windows-${{ matrix.arch }}
path: ./fastfetch-windows-${{ matrix.arch }}.*
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
path: ./fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.*
overwrite: true
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
@@ -652,6 +798,7 @@ jobs:
runs-on: ubuntu-latest
needs:
- linux-hosts
- linux-i686
- linux-armv7l
- linux-armv6l
- linux-vms
@@ -661,7 +808,8 @@ jobs:
- openbsd-amd64
- netbsd-amd64
- dragonfly-amd64
- sunos-amd64
- solaris-amd64
- omnios-amd64
- haiku-amd64
- windows-hosts
permissions:
+251
View File
@@ -1,3 +1,254 @@
# 2.59.0
Changes:
* Fastfetch no longer relies on the unreliable environment variables `$USER` or `%USERPROFILE%` to determine the current username (Title)
* People who set `$USER` to customize the Fastfetch title should use `{ "type": "title", "format": "your-custom-user-name" }` to achieve the same result.
* Fastfetch no longer tries to probe inaccessible remote disk drives on Windows (Disk, Windows)
* People who have remote drives may use `{ "type": "disk", "hideFolders": "X:\\" }` to ignore problematic ones.
* This change removes some ugly hacks from the codebase and matches the behavior on `*nix`.
Features:
* Adds Oracle Solaris support (#2176, SunOS)
* Adds UID / SID detection (Title)
* In custom format: `{user-id}`
* Switches to native GPU detection on GNU/Hurd and removes the `libpciaccess` dependency (GPU, Hurd)
* Improves memory size detection on macOS (Memory, macOS)
* Avoids relying on `hw.memsize_usable` by default, which may not be available on older macOS versions
* Improves Windows disk detection accuracy and performance (Disk, Windows)
* Adds more ARM CPU parts and removes duplicated cases (CPU, ARM)
Logos:
* Adds 6-color support to the NixOS logo (including the small variant) (#2180)
# 2.58.0
An early release to fix compatibility issues with KDE Plasma 6.6.
Breaking changes:
* The `de.slowVersionDetection` option has been removed. Slow version detection is now always enabled, as required on non-FHS-compliant distros (e.g., NixOS). (#2149, DE, Linux)
Features:
* Adds the `--structure-disabled <modules...>` command-line flag to temporarily disable module structure printing.
* For example: `fastfetch --structure-disabled colors` removes the color blocks from the default output.
* Supports chassis type detection on Linux ARM devices when reported via the device tree (Chassis, Linux)
* Supports Bedrock Linux version detection (#2155, OS, Linux)
* Honors the `DBPath` and `RootDir` settings in `pacman.conf` when detecting Pacman packages (#2154, Packages, Linux)
Bugfixes:
* Fixes a crash issues on KDE Plasma 6.6 (Display, Linux)
* Fixes the Command module not working with `--dynamic-interval` (#2152, Command)
* Fixes Quartz Compositor version detection. It now correctly reports the version of `WindowServer` (`SkyLight`) instead of `WindowManager`. (WM, macOS)
Logos:
* Adds Kiss2
# 2.57.1
Features:
* Tiny performance improvements (Windows)
* Improves the reliability of hostname retrieval (Title, Windows)
Bugfixes:
* Fixes potential compilation issues on Linux (#2142, Linux)
* Fixes compilation errors on macOS when building with older SDKs (#2140, macOS)
* Fixes compilation issues when building with `-DENABLE_SYSTEM_YYJSON=ON` (#2143)
Logos:
* Updates PrismLinux and adds a small variant
# 2.57.0
Deprecation notice:
* Support for Windows 7 (and 8.x) is deprecated and will be removed in a future release. Extended support for Windows 7 (and 8.1) ended on January 10, 2023. These versions do not officially support ANSI escape codes (running fastfetch on them requires a third-party terminal such as ConEmu). In addition, Windows 7 lacks some APIs used by fastfetch. Fastfetch currently loads these APIs dynamically at runtime to maintain compatibility, but this adds complexity to the codebase and increases the maintenance burden.
* A CMake flag `ENABLE_WIN7_COMPAT:BOOLEAN` has been introduced (defaults to `ON` for now). If set to `OFF`, Windows 7 compatibility code is excluded, and the resulting binaries will support only Windows 10 (version 1607 and later) and Windows 11.
* The main prebuilt Windows binaries on the Release page (`fastfetch-windows-amd64.*`) are built with `ENABLE_WIN7_COMPAT=OFF`. These are the binaries used by `scoop` and `winget`. Users who need Windows 7 (or 8.x) support can download the `-win7` variant instead.
* The `ENABLE_WIN7_COMPAT` CMake option and the `-win7` variant binaries are planned to be removed in 2.60.0.
Features:
* Supports COSMIC DE version detection (DE, Linux)
* Supports niri version detection (#2121, WM, Linux)
* Supports cosmic-term version and terminal font detection (Terminal / TerminalFont, Linux)
* Supports urxvt font detection (TerminalFont, Linux) (#2105)
* Improves xterm font detection by checking `xterm.vt100.faceName` (TerminalFont, Linux)
* Supports Secure Boot detection (Bootmgr, macOS)
* Supports DPI scale factor detection on Windows 7 (Display, Windows)
* Supports xterm 256-color codes in color configuration
* In `display.color`: "`@<color-index>`" (e.g., "`@34`" for color index `34`)
* In `*.format` strings: "`#@<color-index>`" (e.g., "`#@34`" for color index `34`)
* Improves uptime accuracy on Windows 10+ (Uptime, Windows)
* Adds a new module `Logo` to query built-in logo raw data in JSON output (Logo)
* Usage: `fastfetch -s logo -l <logo-name> -j # Supported in JSON format only`
* Supports shell version detection even if the binary has been deleted (#2136, Shell, Linux)
* Overall code refinements and optimizations
Bugfixes:
* Skips local / loopback routes when detecting network interfaces (LocalIP, Linux) (#2127)
* Fixes CPU speed detection on s390x (CPU, Linux) (#2129)
* Fixes GPU detection error handling and supports case-insensitive PCI ID parsing (GPU, Windows)
* Fixes some networking issues and memory leaks (Networking)
* Fixes `exePath` reporting relative paths on macOS (Shell, macOS)
Logos:
* Adds openSUSE Tumbleweed braille logo
* Adds Xinux
* Renames HydraPWK to NetHydra
* Fixes colors of deepin and UOS
* Fixes colors of macOS and variants
# 2.56.1
Features:
* Improves compatibility with KDE Plasma 6.5 (#2093, Display)
* Adds a `tempSensor` option to specify the sensor name used for CPU temperature detection (CPU)
* Example: `{ "type": "cpu", "tempSensor": "hwmon0" /* Use /sys/class/hwmon/hwmon0 for temperature detection */ }`
* Refines Memory usage detection on macOS to match Activity Monitor more closely (Memory, macOS)
* Minor optimizations
Bugfixes:
* Fixes cache line size detection (CPU, macOS)
Logos:
* Removes Opak
* Updates GXDE
# 2.56.0
Features:
* Enhances config file loading. `--config` and `-c` with relative path now also searches paths defined in `fastfetch --list-config-paths` (typically `~/.config/fastfetch/`)
* This allows users to use `fastfetch -c my-config` without needing to specify the full path.
* Adds NUMA node count detection (CPU)
* Exposed via `{numa-nodes}` in custom format
* Supported on Linux, FreeBSD and Windows
* Supports the newest Alacritty config format (#2070, TerminalFont)
* Detects driver specific info for Zhaoxin GPUs (GPU, Linux)
* Detects Android OEM UI for certain OSes (DE, Android)
* Improves users detection on Linux (#2064, Users, Linux)
* Adds systemd fallback when utmp is unavailable
* Fixes resource leaks
* Always reports the newest session info
* Adds kiss package manager support (#2072, Packages, Linux)
* Reports `sshd` if `$SSH_TTY` is not available (Terminal)
* Zpool module rewrite (#2051, Zpool)
* Adds new Zpool properties: allocated, guid, readOnly
* Zpool module now uses runtime lookup for properties to ensure portability
* Adds NetBSD (requires `sudo`) and macOS support
* Adds `splitLines` option for Command module, which splits the output into sub modules, each containing one line of the output (Command)
```
* Command output:
Line 1
Line 2
Line 3
* Old behavior:
Command: Line 1
Line 2
Line 3
* With `"splitLines": true`:
Command 1: Line 1
Command 2: Line 2
Command 3: Line 3
```
Bugfixes:
* Fixes {m,o}ksh version detection on Linux (Shell)
* Fixes Alacritty config parsing for TOML format (#2070, TerminalFont)
* Improves builtin logo printing for piping and buffering (#2065, Logo)
* Uses absolute path when detecting shell and terminal version if available (#2067, TerminalShell)
Logos:
* Updates Codex Linux logo (#2071)
* Adds OS/2 Warp logo (#2062)
* Adds Amiga logo (#2061)
# 2.55.1
Bugfixes:
* Fix parallel command execution breaks randomly (#2056 / #2058, Command)
* Regression from v2.55.0
* Fix `dylib` searching path on macOS (macOS)
* Regression from v2.55.0
* Fix an uninitialized field (#2057, Display)
# 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:
+242 -195
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.53.0
VERSION 2.59.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 #
###################
@@ -81,8 +92,6 @@ 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 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" OFF)
option(ENABLE_ZLIB "Enable zlib" ON)
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
@@ -95,6 +104,14 @@ 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)
option(ENABLE_LIBZFS "Enable libzfs" ON)
if(WIN32 AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
option(ENABLE_WIN7_COMPAT "Enable Windows 7 compatibility" ON)
endif()
if(APPLE)
option(ENABLE_APPLE_MEMSIZE_USABLE "Use usable memory size as total memory size in Memory module, to match other systems" OFF)
endif()
set(BINARY_LINK_TYPE_OPTIONS dlopen dynamic static)
set(BINARY_LINK_TYPE dlopen CACHE STRING "How to link fastfetch")
@@ -149,7 +166,13 @@ if(WIN32 OR Haiku OR ENABLE_DIRECTX_HEADERS)
endif()
if(WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--tsaware -Wl,--build-id -Wl,--subsystem,console:6.1,--major-os-version,6,--minor-os-version,1")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--tsaware -Wl,--build-id")
if(ENABLE_WIN7_COMPAT)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,console,--major-os-version,6,--minor-os-version,1")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,console,--major-os-version,10,--minor-os-version,0")
endif()
elseif(APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-arc")
endif()
@@ -330,7 +353,7 @@ fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
configure_file(src/fastfetch_config.h.in fastfetch_config.h @ONLY)
configure_file(src/fastfetch_datatext.h.in fastfetch_datatext.h @ONLY)
if(APPLE)
configure_file(src/util/apple/Info.plist.in Info.plist @ONLY)
configure_file(src/common/apple/Info.plist.in Info.plist @ONLY)
endif()
####################
@@ -352,31 +375,39 @@ file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
#######################
set(LIBFASTFETCH_SRC
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/common/impl/commandoption.c
src/common/impl/duration.c
src/common/impl/font.c
src/common/impl/format.c
src/common/impl/frequency.c
src/common/impl/init.c
src/common/impl/jsonconfig.c
src/common/impl/library.c
src/common/impl/netif.c
src/common/impl/networking_common.c
src/common/impl/option.c
src/common/impl/parsing.c
src/common/impl/percent.c
src/common/impl/printing.c
src/common/impl/properties.c
src/common/impl/settings.c
src/common/impl/size.c
src/common/impl/temps.c
src/common/impl/time.c
src/common/impl/edidHelper.c
src/common/impl/base64.c
src/common/impl/FFlist.c
src/common/impl/FFstrbuf.c
src/common/impl/kmod.c
src/common/impl/path.c
src/common/impl/FFPlatform.c
src/common/impl/smbiosHelper.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
@@ -397,6 +428,7 @@ set(LIBFASTFETCH_SRC
src/detection/version/version.c
src/detection/vulkan/vulkan.c
src/detection/weather/weather.c
src/detection/zpool/zpool.c
src/logo/builtin.c
src/logo/image/im6.c
src/logo/image/im7.c
@@ -438,6 +470,7 @@ set(LIBFASTFETCH_SRC
src/modules/loadavg/loadavg.c
src/modules/locale/locale.c
src/modules/localip/localip.c
src/modules/logo/logo.c
src/modules/memory/memory.c
src/modules/monitor/monitor.c
src/modules/netio/netio.c
@@ -475,26 +508,21 @@ set(LIBFASTFETCH_SRC
src/modules/wm/wm.c
src/modules/wmtheme/wmtheme.c
src/modules/zpool/zpool.c
src/modules/modules.c
src/options/display.c
src/options/logo.c
src/options/general.c
src/util/edidHelper.c
src/util/base64.c
src/util/FFlist.c
src/util/FFstrbuf.c
src/util/kmod.c
src/util/path.c
src/util/platform/FFPlatform.c
src/util/smbiosHelper.c
)
if(LINUX)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_linux.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/impl/dbus.c
src/common/impl/io_unix.c
src/common/impl/netif_linux.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/detection/battery/battery_linux.c
src/detection/bios/bios_linux.c
src/detection/board/board_linux.c
@@ -569,17 +597,16 @@ if(LINUX)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
src/detection/zpool/zpool_linux.c
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
)
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/networking_linux.c
src/common/processing_linux.c
src/common/impl/dbus.c
src/common/impl/io_unix.c
src/common/impl/netif_linux.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/detection/battery/battery_android.c
src/detection/bios/bios_android.c
src/detection/bluetooth/bluetooth_nosupport.c
@@ -643,18 +670,17 @@ elseif(ANDROID)
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
src/util/binary_linux.c
)
elseif(FreeBSD)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_bsd.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/common/impl/dbus.c
src/common/impl/io_unix.c
src/common/impl/netif_bsd.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/sysctl.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/detection/battery/battery_bsd.c
src/detection/bios/bios_bsd.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
@@ -726,9 +752,6 @@ elseif(FreeBSD)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
src/detection/zpool/zpool_linux.c
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
)
if(DragonFly)
list(APPEND LIBFASTFETCH_SRC
@@ -743,12 +766,14 @@ elseif(FreeBSD)
endif()
elseif(NetBSD)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_bsd.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/common/impl/dbus.c
src/common/impl/io_unix.c
src/common/impl/netif_bsd.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/sysctl.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/detection/battery/battery_nbsd.c
src/detection/bios/bios_nbsd.c
src/detection/bluetooth/bluetooth_bsd.c
@@ -782,7 +807,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
@@ -820,18 +845,18 @@ elseif(NetBSD)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
src/detection/zpool/zpool_linux.c
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
)
elseif(OpenBSD)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_bsd.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/common/impl/dbus.c
src/common/impl/io_unix.c
src/common/impl/netif_bsd.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/sysctl.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/common/impl/smbiosHelper.c
src/detection/battery/battery_obsd.c
src/detection/bios/bios_windows.c
src/detection/bluetooth/bluetooth_nosupport.c
@@ -866,7 +891,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
@@ -903,18 +928,19 @@ elseif(OpenBSD)
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_apple.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/sysctl.c
src/common/impl/io_unix.c
src/common/impl/netif_apple.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/sysctl.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_apple.c
src/common/apple/cf_helpers.c
src/common/apple/osascript.m
src/common/apple/smc_temps.c
src/detection/battery/battery_apple.c
src/detection/bios/bios_apple.c
src/detection/bluetooth/bluetooth_apple.m
@@ -963,7 +989,7 @@ 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/theme/theme_apple.c
src/detection/tpm/tpm_apple.c
src/detection/uptime/uptime_bsd.c
src/detection/users/users_linux.c
@@ -973,19 +999,22 @@ elseif(APPLE)
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_apple.m
src/detection/camera/camera_apple.m
src/detection/zpool/zpool_nosupport.c
src/util/apple/cf_helpers.c
src/util/apple/osascript.m
src/util/apple/smc_temps.c
src/util/platform/FFPlatform_unix.c
src/util/binary_apple.c
)
elseif(WIN32)
list(APPEND LIBFASTFETCH_SRC
src/common/io/io_windows.c
src/common/netif/netif_windows.c
src/common/networking/networking_windows.c
src/common/processing_windows.c
src/common/impl/io_windows.c
src/common/impl/netif_windows.c
src/common/impl/networking_windows.c
src/common/impl/processing_windows.c
src/common/impl/FFPlatform_windows.c
src/common/impl/binary_windows.c
src/common/impl/debug_windows.c
src/common/windows/getline.c
src/common/windows/com.cpp
src/common/windows/registry.c
src/common/windows/unicode.c
src/common/windows/wmi.cpp
src/common/windows/version.c
src/detection/battery/battery_windows.c
src/detection/bios/bios_windows.c
src/detection/bluetooth/bluetooth_windows.c
@@ -1024,7 +1053,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
@@ -1033,7 +1062,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
@@ -1043,24 +1072,16 @@ elseif(WIN32)
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_windows.c
src/detection/camera/camera_windows.cpp
src/detection/zpool/zpool_nosupport.c
src/util/windows/getline.c
src/util/windows/com.cpp
src/util/windows/registry.c
src/util/windows/unicode.c
src/util/windows/wmi.cpp
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_apple.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/impl/dbus.c
src/common/impl/io_unix.c
src/common/impl/netif_apple.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/detection/battery/battery_nosupport.c
src/detection/bios/bios_windows.c
src/detection/board/board_windows.c
@@ -1132,17 +1153,17 @@ elseif(SunOS)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_nosupport.c
src/detection/zpool/zpool_linux.c
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
)
elseif(Haiku)
list(APPEND LIBFASTFETCH_SRC
src/common/dbus.c
src/common/io/io_unix.c
src/common/netif/netif_haiku.c
src/common/networking/networking_linux.c
src/common/processing_linux.c
src/common/impl/dbus.c
src/common/impl/io_unix.c
src/common/impl/netif_haiku.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/common/haiku/version.cpp
src/detection/battery/battery_haiku.c
src/detection/bios/bios_windows.c
src/detection/board/board_windows.c
@@ -1201,18 +1222,16 @@ elseif(Haiku)
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_nosupport.c
src/detection/camera/camera_nosupport.c
src/detection/zpool/zpool_nosupport.c
src/util/platform/FFPlatform_unix.c
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/common/impl/dbus.c
src/common/impl/io_unix.c
src/common/impl/netif_gnu.c
src/common/impl/networking_linux.c
src/common/impl/processing_linux.c
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/detection/battery/battery_nosupport.c
src/detection/bios/bios_nosupport.c
src/detection/board/board_nosupport.c
@@ -1242,7 +1261,7 @@ elseif(GNU)
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_nosupport.c
src/detection/gpu/gpu_gnu.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_nosupport.c
@@ -1281,9 +1300,6 @@ elseif(GNU)
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()
@@ -1304,11 +1320,15 @@ endif()
include(CheckFunctionExists)
check_function_exists(wcwidth HAVE_WCWIDTH)
if(NOT HAVE_WCWIDTH)
list(APPEND LIBFASTFETCH_SRC src/util/wcwidth.c)
list(APPEND LIBFASTFETCH_SRC src/common/impl/wcwidth.c)
endif()
if(NOT WIN32)
check_function_exists(pipe2 HAVE_PIPE2)
endif()
check_function_exists(memrchr HAVE_MEMRCHR)
if(NOT HAVE_MEMRCHR)
list(APPEND LIBFASTFETCH_SRC src/common/impl/memrchr.c)
endif()
if(ENABLE_SYSTEM_YYJSON)
find_package(yyjson)
@@ -1327,16 +1347,25 @@ add_library(libfastfetch OBJECT
${LIBFASTFETCH_SRC}
)
include(CheckCSourceCompiles)
check_c_source_compiles("int main(void){int arr[1];return _Countof(arr);}" COMPILER_SUPPORTS_COUNT_OF)
if(COMPILER_SUPPORTS_COUNT_OF)
message(STATUS "_Countof is supported by the compiler")
target_compile_definitions(libfastfetch PUBLIC FF_SUPPORTS_COUNT_OF=1)
else()
message(STATUS "_Countof is NOT supported by the compiler")
endif()
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 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)
@@ -1398,7 +1427,7 @@ elseif(OpenBSD)
elseif(DragonFly)
target_compile_definitions(libfastfetch PUBLIC __FreeBSD__)
elseif(SunOS)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE _XOPEN_SOURCE __STDC_WANT_LIB_EXT1__ _FILE_OFFSET_BITS=64 __EXTENSIONS__ _POSIX_C_SOURCE)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE __STDC_WANT_LIB_EXT1__ _FILE_OFFSET_BITS=64 __EXTENSIONS__ _POSIX_C_SOURCE)
elseif(NetBSD)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-char-subscripts")
@@ -1406,9 +1435,39 @@ elseif(NetBSD)
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)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=0)
endif()
if(APPLE)
if(ENABLE_APPLE_MEMSIZE_USABLE)
target_compile_definitions(libfastfetch PUBLIC FF_APPLE_MEMSIZE_USABLE=1)
else()
target_compile_definitions(libfastfetch PUBLIC FF_APPLE_MEMSIZE_USABLE=0)
endif()
endif()
if(WIN32)
check_function_exists(_msize HAVE_MSVC_MSIZE)
if(HAVE_MSVC_MSIZE)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_MSVC_MSIZE=1)
endif()
if(ENABLE_WIN7_COMPAT)
target_compile_definitions(libfastfetch PUBLIC FF_WIN7_COMPAT=1)
else()
target_compile_definitions(libfastfetch PUBLIC FF_WIN7_COMPAT=0)
endif()
else()
check_function_exists(malloc_usable_size HAVE_MALLOC_USABLE_SIZE)
if(HAVE_MALLOC_USABLE_SIZE)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_MALLOC_USABLE_SIZE=1)
else()
check_function_exists(malloc_size HAVE_MALLOC_SIZE)
if(HAVE_MALLOC_SIZE)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_MALLOC_SIZE=1)
endif()
endif()
endif()
if(FreeBSD OR OpenBSD OR NetBSD)
@@ -1594,28 +1653,6 @@ ff_lib_enable(DIRECTX_HEADERS
"DirectX-Headers"
"DirectX-Headers"
)
ff_lib_enable(PCIACCESS
"pciaccess"
"pciaccess"
)
# The system <libzfs.h> is only usable on SunOS. We provide our local copy of it so it's always available.
if(ENABLE_LIBZFS)
if(BINARY_LINK_TYPE STREQUAL "dlopen")
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LIBZFS=1)
else()
set(CMAKE_REQUIRED_LIBRARIES_BACKUP ${CMAKE_REQUIRED_LIBRARIES})
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} zfs)
check_function_exists("libzfs_init" LIBZFS_FOUND)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_BACKUP})
if(NOT LIBZFS_FOUND)
message(STATUS "Library: missing: LIBZFS")
else()
message(STATUS "Library: found LIBZFS")
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LIBZFS=1)
target_link_libraries(libfastfetch PRIVATE zfs)
endif()
endif()
endif()
if(ENABLE_THREADS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS=1)
@@ -1630,6 +1667,18 @@ endif()
if(ENABLE_EMBEDDED_AMDGPUIDS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EMBEDDED_AMDGPUIDS=1)
endif()
if(ENABLE_LIBZFS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LIBZFS=1)
if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
target_link_libraries(libfastfetch
PRIVATE "zfs"
)
endif()
endif()
if(NOT HAVE_MEMRCHR)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_CUSTOM_MEMRCHR=1)
endif()
if(LINUX)
target_link_libraries(libfastfetch
@@ -1678,12 +1727,10 @@ elseif(WIN32)
PRIVATE "wtsapi32"
PRIVATE "imagehlp"
PRIVATE "cfgmgr32"
PRIVATE "winbrand"
PRIVATE "propsys"
PRIVATE "secur32"
)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
# WoA only works on Windows 10 or higher
if(NOT ENABLE_WIN7_COMPAT)
target_link_libraries(libfastfetch
PRIVATE "mincore"
)
@@ -1721,8 +1768,6 @@ elseif(SunOS)
PRIVATE "socket"
PRIVATE "kstat"
PRIVATE "proc"
PRIVATE "zfs"
PRIVATE "nvpair"
PRIVATE "devinfo"
)
elseif(GNU)
@@ -1733,17 +1778,20 @@ elseif(ANDROID)
target_link_libraries(libfastfetch
PRIVATE "m"
)
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)
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)
@@ -1805,13 +1853,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)
@@ -1866,7 +1918,7 @@ set_target_properties(fastfetch PROPERTIES LINKER_LANGUAGE C)
if(WIN32)
target_sources(fastfetch
PRIVATE src/util/windows/version.rc
PRIVATE src/common/windows/version.rc
)
elseif(APPLE)
target_link_options(fastfetch
@@ -1894,7 +1946,7 @@ if (BUILD_FLASHFETCH)
if(WIN32)
target_sources(flashfetch
PRIVATE src/util/windows/version.rc
PRIVATE src/common/windows/version.rc
)
elseif(APPLE)
target_link_options(flashfetch
@@ -2020,11 +2072,6 @@ install(
##################
set(CPACK_GENERATOR "TGZ;ZIP")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
endif()
if(APPLE)
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) # use macos instead of darwin
elseif(IS_MUSL)
@@ -2064,14 +2111,14 @@ if(LINUX)
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
endif()
endif()
elseif(FreeBSD)
elseif(FreeBSD AND NOT DragonFly)
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.\
+1 -1
View File
@@ -1,7 +1,7 @@
MIT License
Copyright (c) 2021-2023 Linus Dierheimer
Copyright (c) 2022-2025 Carter Li
Copyright (c) 2022-2026 Carter Li
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+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">
+13 -2
View File
@@ -11,8 +11,9 @@
[![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 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.
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, illumos (SunOS), and Solaris.
<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" />
@@ -36,7 +37,8 @@ Some distributions package outdated versions of fastfetch. Older versions receiv
<img src="https://repology.org/badge/vertical-allrepos/fastfetch.svg?columns=2" alt="Packaging status" align="right">
</a>
* Debian: `apt install fastfetch` (for Debian 13 or newer)
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (Ubuntu 22.04 or newer; latest version)
* Debian / Ubuntu: `apt install fastfetch` (Debian 13 or newer; Ubuntu 25.04 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`
* Fedora: `dnf install fastfetch`
@@ -103,6 +105,10 @@ Fastfetch uses JSONC (JSON with comments) for configuration. [See the Wiki for d
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?
@@ -317,6 +323,11 @@ 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 us a star to show your support!
+55 -1
View File
@@ -1,3 +1,58 @@
fastfetch (2.58.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.58.0
-- Carter Li <zhangsongcui@live.cn> Thu, 22 Jan 2026 15:30:58 +0800
fastfetch (2.57.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.57.1
-- Carter Li <zhangsongcui@live.cn> Wed, 14 Jan 2026 14:00:17 +0800
fastfetch (2.57.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.57.0
-- Carter Li <zhangsongcui@live.cn> Mon, 12 Jan 2026 10:11:21 +0800
fastfetch (2.56.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.56.1
-- Carter Li <zhangsongcui@live.cn> Thu, 18 Dec 2025 14:57:36 +0800
fastfetch (2.56.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.56.0
-- Carter Li <zhangsongcui@live.cn> Mon, 08 Dec 2025 09:21:58 +0800
fastfetch (2.55.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.55.1
-- Carter Li <zhangsongcui@live.cn> Mon, 17 Nov 2025 10:15:44 +0800
fastfetch (2.55.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.55.0
-- Carter Li <zhangsongcui@live.cn> Wed, 12 Nov 2025 09:15:24 +0800
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
@@ -435,4 +490,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: 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
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.53.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
+71 -12
View File
@@ -318,7 +318,7 @@
"type": "string"
},
"cpuFormat": {
"description": "Output format of the module `CPU`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: X86-64 CPU microarchitecture",
"description": "Output format of the module `CPU`. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count",
"type": "string"
},
"cpucacheFormat": {
@@ -442,7 +442,7 @@
"type": "string"
},
"packagesFormat": {
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {nix-all}: Total number of all nix packages\n 44. {flatpak-all}: Total number of all flatpak app packages\n 45. {brew-all}: Total number of all brew packages\n 46. {guix-all}: Total number of all guix packages\n 47. {hpkg-all}: Total number of all hpkg packages",
"description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {kiss}: Number of kiss packages\n 44. {nix-all}: Total number of all nix packages\n 45. {flatpak-all}: Total number of all flatpak app packages\n 46. {brew-all}: Total number of all brew packages\n 47. {guix-all}: Total number of all guix packages\n 48. {hpkg-all}: Total number of all hpkg packages",
"type": "string"
},
"physicaldiskFormat": {
@@ -498,7 +498,7 @@
"type": "string"
},
"titleFormat": {
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name",
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name\n 10. {user-id}: UID (*nix) / SID (Windows)\n 11. {pid}: PID of current process",
"type": "string"
},
"themeFormat": {
@@ -546,7 +546,7 @@
"type": "string"
},
"zpoolFormat": {
"description": "Output format of the module `Zpool`. See Wiki for formatting syntax\n 1. {name}: Zpool name\n 2. {state}: Zpool state\n 3. {used}: Size used\n 4. {total}: Size total\n 5. {used-percentage}: Size percentage num\n 6. {fragmentation-percentage}: Fragmentation percentage num\n 7. {used-percentage-bar}: Size percentage bar\n 8. {fragmentation-percentage-bar}: Fragmentation percentage bar",
"description": "Output format of the module `Zpool`. See Wiki for formatting syntax\n 1. {name}: Zpool name\n 2. {guid}: Zpool guid\n 3. {state}: Zpool state\n 4. {used}: Size used\n 5. {allocated}: Size allocated\n 6. {total}: Size total\n 7. {used-percentage}: Size used percentage num\n 8. {allocated-percentage}: Size allocated percentage num\n 9. {fragmentation-percentage}: Fragmentation percentage num\n 10. {used-percentage-bar}: Size used percentage bar\n 11. {allocated-percentage-bar}: Size allocated percentage bar\n 12. {fragmentation-percentage-bar}: Fragmentation percentage bar\n 13. {is-readonly}: Is read-only",
"type": "string"
}
},
@@ -1008,7 +1008,7 @@
},
"type": {
"type": "string",
"description": "Set whether to show icon before string keys",
"description": "Set whether to show builtin icon before string keys",
"oneOf": [
{
"const": "none",
@@ -1020,11 +1020,31 @@
},
{
"const": "icon",
"description": "Show icon keys (requires newest nerd font)"
"description": "Show builtin icon (requires newest nerd font)"
},
{
"const": "both",
"description": "Show both icon and string keys"
"description": "Show both icon and string keys (alias of `both-1`)"
},
{
"const": "both-0",
"description": "Show both icon and string with no spaces between them"
},
{
"const": "both-1",
"description": "Show both icon and string with a space between them"
},
{
"const": "both-2",
"description": "Show both icon and string with 2 spaces between them"
},
{
"const": "both-3",
"description": "Show both icon and string with 3 spaces between them"
},
{
"const": "both-4",
"description": "Show both icon and string with 4 spaces between them"
}
],
"default": "string"
@@ -1860,6 +1880,10 @@
"temp": {
"$ref": "#/$defs/temperature"
},
"tempSensor": {
"description": "Set the temperature sensor to use for CPU temperature detection\n* Linux: `hwmon` or `thermal` path name (eg. `hwmon0`, `thermal_zone0)`\n* macOS: SMC sensor key (eg. `Tp01`)\n* Windows: thermal zone key (eg. `\\_TZ.CPUZ`)\n* FreeBSD: sysctl key (eg. `dev.cpu.0.temperature`)\n* NetBSD: sysmon sensor key (eg. `coretemp0`)",
"type": "string"
},
"showPeCoreCount": {
"description": "Detect and display CPU frequency of different core types (eg. Pcore and Ecore) if supported",
"type": "boolean",
@@ -1975,7 +1999,7 @@
"additionalProperties": false,
"properties": {
"type": {
"description": "Print some colored blocks",
"description": "Display the terminal's 16-color palette",
"const": "colors"
},
"symbol": {
@@ -2081,6 +2105,21 @@
"description": "Set the command text to be executed",
"type": "string"
},
"useStdErr": {
"description": "Set if stderr should be used instead of stdout for command output",
"type": "boolean",
"default": false
},
"parallel": {
"description": "Set if the command should be executed in parallel with other commands\nImprove performance when using multiple commands, but may cause issues with some commands",
"type": "boolean",
"default": true
},
"splitLines": {
"description": "Set if the command output should be split into multiple lines",
"type": "boolean",
"default": false
},
"key": {
"$ref": "#/$defs/key"
},
@@ -2326,7 +2365,7 @@
]
},
"hideFolders": {
"description": "A list of folder paths to hide from the disk output",
"description": "A list of folder paths (or glob patterns) to hide from the disk output",
"oneOf": [
{
"type": "string",
@@ -2342,7 +2381,7 @@
"uniqueItems": true
}
],
"default": "/efi:/boot:/boot/efi:/boot/firmware"
"default": "/efi:/boot:/boot/*"
},
"hideFS": {
"description": "A list of file systems to hide from the disk output",
@@ -2925,8 +2964,11 @@
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"outputColor": {
"$ref": "#/$defs/outputColor"
},
"format": {
"$ref": "#/$defs/memoryFormat"
"$ref": "#/$defs/keyboardFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
@@ -3160,6 +3202,20 @@
}
}
},
{
"title": "Logo",
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"const": "logo",
"description": "Query built-in logo for JSON output"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
{
"title": "Media",
"type": "object",
@@ -3257,8 +3313,11 @@
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"outputColor": {
"$ref": "#/$defs/outputColor"
},
"format": {
"$ref": "#/$defs/memoryFormat"
"$ref": "#/$defs/mouseFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
+1
View File
@@ -109,6 +109,7 @@
},
"tpm",
"version",
"logo",
"break",
"colors"
]
+1 -1
View File
@@ -1,4 +1,4 @@
// Load with --load-config examples/2.jsonc
// Load with --config examples/2.jsonc
// Note that you must replace the image path to an existing image to display it.
{
+1 -1
View File
@@ -1,4 +1,4 @@
// Load with --load-config examples/2.jsonc
// Load with --config examples/2.jsonc
// Note that you must replace the image path to an existing image to display it.
{
+1 -1
View File
@@ -183,7 +183,7 @@
},
"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 {}"
},
{
+1 -1
View File
@@ -1,4 +1,4 @@
// Load with --load-config examples/3.jsonc
// Load with --config examples/3.jsonc
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,4 +1,4 @@
// Load with --load-config examples/4.jsonc
// Load with --config examples/4.jsonc
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
+1 -1
View File
@@ -1,4 +1,4 @@
// Load with --load-config examples/5.jsonc
// Load with --config examples/5.jsonc
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
+1 -1
View File
@@ -1,4 +1,4 @@
// Load with --load-config examples/2.jsonc
// Load with --config examples/2.jsonc
// Note that you must replace the image path to an existing image to display it.
{
+1 -1
View File
@@ -1,4 +1,4 @@
// Load with --load-config examples/2.jsonc
// Load with --config examples/2.jsonc
// Note that you must replace the image path to an existing image to display it.
{
@@ -1,7 +1,7 @@
#pragma once
#include "util/FFstrbuf.h"
#include "util/FFlist.h"
#include "common/FFstrbuf.h"
#include "common/FFlist.h"
typedef struct FFPlatformSysinfo
{
@@ -9,7 +9,6 @@ typedef struct FFPlatformSysinfo
FFstrbuf release;
FFstrbuf version;
FFstrbuf architecture;
FFstrbuf displayVersion;
uint32_t pageSize;
} FFPlatformSysinfo;
@@ -19,8 +18,14 @@ typedef struct FFPlatform
FFstrbuf cacheDir; // Trailing slash included
FFlist configDirs; // List of FFstrbuf, trailing slash included
FFlist dataDirs; // List of FFstrbuf, trailing slash included
FFstrbuf exePath; // The real path of current exe
FFstrbuf exePath; // The real path of current exe (empty if unavailable)
uint32_t pid;
#ifndef _WIN32
uint32_t uid;
#else
FFstrbuf sid;
#endif
FFstrbuf userName;
FFstrbuf fullUserName;
FFstrbuf hostName;
@@ -126,3 +126,10 @@ static inline void ffListClear(FFlist* list)
assert(sizeof(itemType) == (listVar).elementSize); \
(itemType*) ffListAdd(&(listVar)); \
})
#define FF_LIST_FIRST(itemType, listVar) FF_LIST_GET(itemType, listVar, 0)
#define FF_LIST_LAST(itemType, listVar) \
({ \
assert((listVar).length > 0); \
FF_LIST_GET(itemType, listVar, ((listVar).length - 1)); \
})
+81 -53
View File
@@ -24,6 +24,8 @@
#define FASTFETCH_STRBUF_DEFAULT_ALLOC 32
// static string (allocated == 0), chars points to a string literal
// dynamic string (allocated > 0), chars points to a heap allocated buffer
typedef struct FFstrbuf
{
uint32_t allocated;
@@ -34,6 +36,7 @@ typedef struct FFstrbuf
static inline void ffStrbufInit(FFstrbuf* strbuf);
void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate);
void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments);
void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr);
void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free);
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free);
@@ -54,6 +57,10 @@ void ffStrbufPrependC(FFstrbuf* strbuf, char c);
void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c);
// Clear the content of strbuf and set new value
// NOTE: Unlike ffStrbufAppend*, ffStrbufSet* functions may NOT reserve extra space
void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value);
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value);
FF_C_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
@@ -96,8 +103,41 @@ FF_C_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultV
void ffStrbufUpperCase(FFstrbuf* strbuf);
void ffStrbufLowerCase(FFstrbuf* strbuf);
bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer);
void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer);
// Function alters the buffer to extract lines or delimited segments (replaces the delimiter with '\0')
// so that buffer MUST be heap allocated (NOT a static string)
// `lineptr` must be `NULL` and `n` MUST be `0` for the first call
// Caller MUST NOT free `*lineptr`
bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer);
void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer);
/**
* @brief Read a line from a FFstrbuf.
*
* @details Behaves like getline(3) but reads from a FFstrbuf.
*
* @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line
(points to buffer's internal memory address to avoid memory allocation and copy).
MUST NOT be freed by the caller, unlike `getline(3)`.
* MUST be NULL for the first call.
* @param[in,out] n The pointer to the size of the buffer of lineptr.
MUST be 0 for the first call.
* @param[in] buffer The buffer to read from.
MUST be heap allocated (NOT a static string).
*
* @return true if a line has been read, false if the end of the buffer has been reached.
*/
static inline bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
{
return ffStrbufGetdelim(lineptr, n, '\n', buffer);
}
/**
* @brief Restore the end of a line that was modified by ffStrbufGetline.
* @warning This function should be called before breaking an ffStrbufGetline loop if `buffer` will be used later.
*/
static inline void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer)
{
ffStrbufGetdelimRestore(lineptr, n, '\n', buffer);
}
bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf);
bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
@@ -122,7 +162,7 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict src)
{
if (src->allocated == 0) // static string
memcpy(strbuf, src, sizeof(FFstrbuf));
*strbuf = *src;
else
{
ffStrbufInitA(strbuf, src->allocated);
@@ -142,9 +182,7 @@ static inline void ffStrbufInitMove(FFstrbuf* strbuf, FFstrbuf* src)
{
if (src)
{
strbuf->allocated = src->allocated;
strbuf->chars = src->chars;
strbuf->length = src->length;
*strbuf = *src;
ffStrbufInit(src);
}
else
@@ -187,21 +225,17 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateF(const char* format, ...)
return strbuf;
}
static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr)
{
ffStrbufInitMoveNS(strbuf, (uint32_t) strlen(heapStr), heapStr);
}
static inline void ffStrbufDestroy(FFstrbuf* strbuf)
{
extern char* CHAR_NULL_PTR;
if(strbuf->allocated > 0)
free(strbuf->chars);
if(strbuf->allocated == 0)
{
strbuf->length = 0;
strbuf->chars = CHAR_NULL_PTR;
return;
}
//Avoid free-after-use. These 3 assignments are cheap so don't remove them
strbuf->allocated = strbuf->length = 0;
free(strbuf->chars);
strbuf->chars = CHAR_NULL_PTR;
ffStrbufInit(strbuf);
}
FF_C_NODISCARD static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf)
@@ -218,6 +252,30 @@ static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf)
strbuf->length = (uint32_t) strlen(strbuf->chars);
}
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value)
{
assert(strbuf != NULL);
if (value == NULL)
ffStrbufClear(strbuf);
else
ffStrbufSetNS(strbuf, (uint32_t) strlen(value), value);
}
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
{
assert(strbuf != NULL);
if (yyjson_is_str(jsonVal))
{
ffStrbufSetNS(strbuf, (uint32_t) unsafe_yyjson_get_len(jsonVal), unsafe_yyjson_get_str(jsonVal));
return true;
}
ffStrbufClear(strbuf);
return false;
}
static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value)
{
if(value == NULL)
@@ -235,42 +293,10 @@ static inline bool ffStrbufAppendJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
return false;
}
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value)
{
ffStrbufClear(strbuf);
if(value != NULL)
ffStrbufAppendNS(strbuf, (uint32_t) strlen(value), value);
}
static inline void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value)
{
ffStrbufClear(strbuf);
ffStrbufAppendNS(strbuf, length, value);
}
static inline void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value)
{
assert(value && value != strbuf);
if (strbuf->allocated == 0 && value->allocated == 0)
{
memcpy(strbuf, value, sizeof(FFstrbuf));
return;
}
ffStrbufSetNS(strbuf, value->length, value->chars);
}
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
{
ffStrbufClear(strbuf);
return ffStrbufAppendJsonVal(strbuf, jsonVal);
}
static inline void ffStrbufInit(FFstrbuf* strbuf)
{
extern char* CHAR_NULL_PTR;
strbuf->allocated = 0;
strbuf->length = 0;
strbuf->allocated = strbuf->length = 0;
strbuf->chars = CHAR_NULL_PTR;
}
@@ -301,10 +327,12 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateStatic(const char* str)
static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value)
{
if(strbuf->allocated > 0)
ffStrbufDestroy(strbuf);
free(strbuf->chars);
if(value != NULL)
ffStrbufInitStatic(strbuf, value);
else
ffStrbufInit(strbuf);
}
static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char* str)
@@ -361,7 +389,7 @@ static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value)
ffStrbufPrependNS(strbuf, (uint32_t) strlen(value), value);
}
static inline int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
static inline FF_C_NODISCARD int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
{
uint32_t length = strbuf->length > comp->length ? comp->length : strbuf->length;
return memcmp(strbuf->chars, comp->chars, length + 1);
@@ -40,11 +40,9 @@ const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result)
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
{
ffStrbufClear(result);
if (!cf)
{
ffStrbufClear(result);
return NULL;
}
if (CFGetTypeID(cf) == CFStringGetTypeID())
{
@@ -56,6 +54,8 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
else
{
uint32_t length = (uint32_t) CFStringGetLength(cfStr);
if (length == 0)
return NULL;
ffStrbufEnsureFixedLengthFree(result, (uint32_t) CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8));
if(!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8))
return "CFStringGetCString() failed";
@@ -68,7 +68,9 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
{
CFDataRef cfData = (CFDataRef)cf;
uint32_t length = (uint32_t)CFDataGetLength(cfData);
ffStrbufEnsureFree(result, length + 1);
if (length == 0)
return NULL;
ffStrbufEnsureFixedLengthFree(result, length + 1);
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars);
result->length = (uint32_t)strnlen(result->chars, length);
result->chars[result->length] = '\0';
@@ -79,6 +81,29 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
return NULL;
}
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result)
{
ffStrbufClear(result);
if (!cf)
return NULL;
if (CFGetTypeID(cf) == CFDataGetTypeID())
{
CFDataRef cfData = (CFDataRef)cf;
uint32_t length = (uint32_t)CFDataGetLength(cfData);
if (length == 0)
return NULL;
ffStrbufEnsureFixedLengthFree(result, length + 1);
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars);
result->length = length;
result->chars[result->length] = '\0';
}
else
return "TypeID is not 'CFData'";
return NULL;
}
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result)
{
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
@@ -88,6 +113,15 @@ const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* r
return ffCfStrGetString(cf, result);
}
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result)
{
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
if(cf == NULL)
return "CFDictionaryGetValue() failed";
return ffCfDataGetDataAsString(cf, result);
}
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result)
{
CFBooleanRef cf = (CFBooleanRef)CFDictionaryGetValue(dict, key);
@@ -8,11 +8,13 @@
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result);
const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result);
const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result);
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result);
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result);
const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result);
const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result);
const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length);
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result);
static inline CFNumberRef ffCfCreateInt(int value)
@@ -22,6 +24,7 @@ static inline CFNumberRef ffCfCreateInt(int value)
static inline void cfReleaseWrapper(void* type)
{
assert(type);
if (*(CFTypeRef*) type)
CFRelease(*(CFTypeRef*) type);
}
@@ -1,6 +1,6 @@
#include "fastfetch.h"
#include "smc_temps.h"
#include "util/stringUtils.h"
#include "common/apple/cf_helpers.h"
#include "common/stringUtils.h"
#include <stdint.h>
#include <math.h>
@@ -137,14 +137,11 @@ static const char *smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcV
static const char *smcOpen(io_connect_t *conn)
{
io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC"));
FF_IOOBJECT_AUTO_RELEASE io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC"));
if (!device)
return "No SMC device found";
kern_return_t result = IOServiceOpen(device, mach_task_self(), 0, conn);
IOObjectRelease(device);
if (result != kIOReturnSuccess)
if (IOServiceOpen(device, mach_task_self(), 0, conn) != kIOReturnSuccess)
return "IOServiceOpen() failed";
return NULL;
@@ -159,113 +156,108 @@ static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl
if (val.dataSize == 0)
return "Empty SMC result";
if (ffStrEquals(val.dataType, "ui8 ") ||
ffStrEquals(val.dataType, "ui16") ||
ffStrEquals(val.dataType, "ui32") ||
ffStrEquals(val.dataType, "ui64"))
switch (val.dataType[0])
{
uint64_t tmp = 0;
for (uint32_t i = 0; i < val.dataSize; i++)
tmp += (uint64_t)((uint8_t)(val.bytes[i]) * pow(256, val.dataSize - 1 - i));
*value = (double)tmp;
case 'u': // unsigned integer types
if (val.dataType[1] == 'i')
{
switch (val.dataSize)
{
case 1: *value = *(uint8_t *)(val.bytes); break;
case 2: *value = ntohs(*(uint16_t *)(val.bytes)); break;
case 4: *value = ntohl(*(uint32_t *)(val.bytes)); break;
case 8: *value = (double) ntohll(*(uint64_t *)(val.bytes)); break;
default:
return "Unsupported SMC unsigned integer data size";
}
}
else
return "Unsupported SMC unsigned data type";
break;
case 'f': // floating point types
if (ffStrEquals(val.dataType, "flt ") && val.dataSize == 4)
*value = *(float *)(val.bytes);
else if (val.dataType[1] == 'p' && val.dataSize == 2) // fixed point types
{
if (ffStrEquals(val.dataType, "fp1f"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 32768.0;
else if (ffStrEquals(val.dataType, "fp4c"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0;
else if (ffStrEquals(val.dataType, "fp5b"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0;
else if (ffStrEquals(val.dataType, "fp6a"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0;
else if (ffStrEquals(val.dataType, "fp79"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 512.0;
else if (ffStrEquals(val.dataType, "fp88"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 256.0;
else if (ffStrEquals(val.dataType, "fpa6"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 64.0;
else if (ffStrEquals(val.dataType, "fpc4"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 16.0;
else if (ffStrEquals(val.dataType, "fpe2"))
*value = ntohs(*(uint16_t *)(val.bytes)) / 4.0;
else
return "Unsupported SMC floating point data type";
}
else
return "Unsupported SMC floating point data type";
break;
case 's': // signed integer types
if (val.dataType[1] == 'i')
{
switch (val.dataSize)
{
case 1: *value = *(int8_t *)(val.bytes); break;
case 2: *value = ntohs(*(int16_t *)(val.bytes)); break;
case 4: *value = ntohl(*(int32_t *)(val.bytes)); break;
case 8: *value = (double)ntohll(*(int64_t *)(val.bytes)); break;
default: return "Unsupported SMC signed integer data size";
}
}
else if (val.dataType[1] == 'p' && val.dataSize == 2) // signed fixed point types
{
if (ffStrEquals(val.dataType, "sp1e"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 16384.0;
else if (ffStrEquals(val.dataType, "sp3c"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 4096.0;
else if (ffStrEquals(val.dataType, "sp4b"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 2048.0;
else if (ffStrEquals(val.dataType, "sp5a"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 1024.0;
else if (ffStrEquals(val.dataType, "sp69"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 512.0;
else if (ffStrEquals(val.dataType, "sp78"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 256.0;
else if (ffStrEquals(val.dataType, "sp87"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 128.0;
else if (ffStrEquals(val.dataType, "sp96"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 64.0;
else if (ffStrEquals(val.dataType, "spb4"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 16.0;
else if (ffStrEquals(val.dataType, "spf0"))
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 1.0;
else
return "Unsupported SMC signed integer data type";
}
else
return "Unsupported SMC signed data type";
break;
case '{': // special types like pwm
if (ffStrEquals(val.dataType, "{pwm") && val.dataSize == 2)
{
*value = (double)ntohs(*(uint16_t *)(val.bytes)) * 100 / 65536.0;
}
else
return "Unsupported SMC special data type";
break;
default:
return "Unsupported SMC data type";
}
else if (ffStrEquals(val.dataType, "flt "))
{
*value = *(float *)(val.bytes);
}
else if (ffStrEquals(val.dataType, "fp1f") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 32768.0;
}
else if (ffStrEquals(val.dataType, "fp4c") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0;
}
else if (ffStrEquals(val.dataType, "fp5b") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0;
}
else if (ffStrEquals(val.dataType, "fp6a") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0;
}
else if (ffStrEquals(val.dataType, "fp79") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 512.0;
}
else if (ffStrEquals(val.dataType, "fp88") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 256.0;
}
else if (ffStrEquals(val.dataType, "fpa6") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 64.0;
}
else if (ffStrEquals(val.dataType, "fpc4") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 16.0;
}
else if (ffStrEquals(val.dataType, "fpe2") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 4.0;
}
else if (ffStrEquals(val.dataType, "sp1e") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 16384.0;
}
else if (ffStrEquals(val.dataType, "sp3c") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0;
}
else if (ffStrEquals(val.dataType, "sp4b") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0;
}
else if (ffStrEquals(val.dataType, "sp5a") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0;
}
else if (ffStrEquals(val.dataType, "sp69") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 512.0;
}
else if (ffStrEquals(val.dataType, "sp78") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 256.0;
}
else if (ffStrEquals(val.dataType, "sp87") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 128.0;
}
else if (ffStrEquals(val.dataType, "sp96") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 64.0;
}
else if (ffStrEquals(val.dataType, "spb4") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 16.0;
}
else if (ffStrEquals(val.dataType, "spf0") && val.dataSize == 2)
{
*value = ntohs(*(uint16_t *)(val.bytes)) / 1.0;
}
else if (ffStrEquals(val.dataType, "si8 ") && val.dataSize == 1)
{
signed char *bytes = (signed char *)val.bytes;
int16_t temp = 0;
temp += (int8_t)(bytes[0]);
*value = temp;
}
else if (ffStrEquals(val.dataType, "si16") && val.dataSize == 2)
{
*value = ntohs(*(int16_t *)(val.bytes));
}
else if (ffStrEquals(val.dataType, "{pwm") && val.dataSize == 2)
{
*value = (double)ntohs(*(uint16_t *)(val.bytes)) * 100 / 65536.0;
}
else
return "Unknown SMC data type";
return NULL;
}
@@ -280,15 +272,32 @@ static bool detectTemp(io_connect_t conn, const char* sensor, double* sum)
return true;
}
const char* ffDetectSmcTemps(enum FFTempType type, double* result)
static io_connect_t conn;
const char* ffDetectSmcSpecificTemp(const char* sensor, double* result)
{
static io_connect_t conn;
if (!conn)
{
if (smcOpen(&conn) != NULL)
conn = (io_connect_t) -1;
}
else if (conn == (io_connect_t) -1)
if (conn == (io_connect_t) -1)
return "Could not open SMC connection";
if (!detectTemp(conn, sensor, result))
return "Could not read SMC temperature";
return NULL;
}
const char* ffDetectSmcTemps(enum FFTempType type, double* result)
{
if (!conn)
{
if (smcOpen(&conn) != NULL)
conn = (io_connect_t) -1;
}
if (conn == (io_connect_t) -1)
return "Could not open SMC connection";
uint32_t count = 0;
@@ -30,4 +30,5 @@ enum FFTempType
FF_TEMP_MEMORY,
};
const char* ffDetectSmcSpecificTemp(const char* sensor, double* result);
const char* ffDetectSmcTemps(enum FFTempType type, double* result);
@@ -3,7 +3,9 @@
#include <assert.h>
#ifdef __has_builtin
#if __has_builtin(__is_array)
#if !__cplusplus && FF_SUPPORTS_COUNT_OF
#define ARRAY_SIZE(x) _Countof(x)
#elif __has_builtin(__is_array)
#define ARRAY_SIZE(x) ({ static_assert(__is_array(__typeof__(x)), "Must be an array"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
#elif __has_builtin(__builtin_types_compatible_p)
#define ARRAY_SIZE(x) ({ static_assert(!__builtin_types_compatible_p(__typeof__(x), __typeof__(&*(x))), "Must not be a pointer"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
+3 -10
View File
@@ -1,15 +1,8 @@
#pragma once
#include "fastfetch.h"
// Things only needed by fastfetch
typedef struct FFdata
{
FFstrbuf structure;
bool configLoaded;
} FFdata;
#include "common/ffdata.h"
void ffPrepareCommandOption(FFdata* data);
void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc);
void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc);
void ffPrintCommandOption(FFdata* data);
void ffMigrateCommandOptionToJsonc(FFdata* data);
bool ffParseModuleOptions(const char* key, const char* value);
+1 -1
View File
@@ -3,7 +3,7 @@
#ifdef FF_HAVE_DBUS
#include <dbus/dbus.h>
#include "util/FFstrbuf.h"
#include "common/FFstrbuf.h"
#include "common/library.h"
typedef struct FFDBusLibrary
+2
View File
@@ -28,4 +28,6 @@ static inline const char* ffFindFileName(const char* file)
#define FF_DEBUG(format, ...) FF_DEBUG_PRINT(__FILE__, __LINE__, format, ##__VA_ARGS__)
#if _WIN32
const char* ffDebugWin32Error(unsigned long errorCode);
#endif
+2
View File
@@ -1,3 +1,5 @@
#pragma once
#include "fastfetch.h"
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result);
@@ -1,7 +1,7 @@
#pragma once
#include <stdint.h>
#include "util/FFstrbuf.h"
#include "common/FFstrbuf.h"
void ffEdidGetVendorAndModel(const uint8_t edid[128], FFstrbuf* result);
bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name);
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include "common/FFstrbuf.h"
typedef enum __attribute__((__packed__)) FFDataResultDocType
{
FF_RESULT_DOC_TYPE_DEFAULT = 0,
FF_RESULT_DOC_TYPE_JSON,
FF_RESULT_DOC_TYPE_CONFIG,
FF_RESULT_DOC_TYPE_CONFIG_FULL,
} FFDataResultDocType;
// FFdata aggregates configuration, generation parameters, and output state used by fastfetch.
// It holds the parsed configuration document, a mutable JSON document for results, and related metadata.
typedef struct FFdata
{
yyjson_doc* configDoc; // Parsed JSON configuration document
yyjson_mut_doc* resultDoc; // Mutable JSON document for storing results
FFstrbuf structure; // Custom output structure from command line
FFstrbuf structureDisabled; // Disabled modules in the output structure from command line
FFstrbuf genConfigPath; // Path to generate configuration file
FFDataResultDocType docType; // Type of result document
bool configLoaded;
} FFdata;
-221
View File
@@ -1,221 +0,0 @@
#include "fastfetch.h"
#include "common/font.h"
#include <string.h>
#include <ctype.h>
void ffFontInit(FFfont* font)
{
// Ensure no memory allocates
ffStrbufInit(&font->pretty);
ffStrbufInit(&font->name);
ffStrbufInit(&font->size);
ffListInit(&font->styles, sizeof(FFstrbuf));
}
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
{
if(value == NULL || length == 0)
return;
ffStrbufEnsureFree(strbuf, length);
for(uint32_t i = 0; i < length; i++)
{
if(value[i] != exclude)
strbuf->chars[strbuf->length++] = value[i];
}
strbuf->chars[strbuf->length] = '\0';
}
static void fontInitPretty(FFfont* font)
{
ffStrbufAppend(&font->pretty, &font->name);
if(font->size.length == 0 && font->styles.length == 0)
return;
else if(font->pretty.length == 0)
ffStrbufAppendS(&font->pretty, "default");
ffStrbufAppendS(&font->pretty, " (");
if(font->size.length > 0)
{
ffStrbufAppend(&font->pretty, &font->size);
ffStrbufAppendS(&font->pretty, "pt");
if(font->styles.length > 0)
ffStrbufAppendS(&font->pretty, ", ");
}
for(uint32_t i = 0; i < font->styles.length; i++)
{
ffStrbufAppend(&font->pretty, FF_LIST_GET(FFstrbuf, font->styles, i));
if(i < font->styles.length - 1)
ffStrbufAppendS(&font->pretty, ", ");
}
ffStrbufAppendC(&font->pretty, ')');
}
void ffFontInitQt(FFfont* font, const char* data)
{
ffFontInit(font);
//See https://doc.qt.io/qt-5/qfont.html#toString
//Family
data = ffStrbufAppendSUntilC(&font->name, data, ',');
ffStrbufTrim(&font->name, ' ');
if (!data) goto exit;
data++;
//Size
data = ffStrbufAppendSUntilC(&font->size, data, ',');
ffStrbufTrim(&font->size, ' ');
if (!data) goto exit;
data++;
//Style
data = strrchr(data, ',');
if (!data) goto exit;
data++;
if (isalpha(*data))
{
do
{
FFstrbuf* style = (FFstrbuf*) ffListAdd(&font->styles);
ffStrbufInit(style);
data = ffStrbufAppendSUntilC(style, data, ' ');
if (data) data++;
} while (data);
}
exit:
fontInitPretty(font);
}
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
{
while(**data == ' ' || **data == '\t' || **data == ',')
++(*data);
const char* wordStart = *data;
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
++(*data);
uint32_t wordLength = (uint32_t) (*data - wordStart);
if(wordLength == 0)
return;
if(**data == '\0' || **data == '`' || **data == '\\')
{
ffStrbufAppendNS(&font->size, wordLength, wordStart);
if(ffStrbufEndsWithS(&font->size, "px"))
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
double dummy;
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
return;
ffStrbufClear(&font->size);
}
if(
strncasecmp(wordStart, "Ultra", 5) == 0 ||
strncasecmp(wordStart, "Extra", 5) == 0 ||
strncasecmp(wordStart, "Semi", 4) == 0 ||
strncasecmp(wordStart, "Demi", 4) == 0 ||
strncasecmp(wordStart, "Normal", wordLength) == 0 ||
strncasecmp(wordStart, "Roman", wordLength) == 0 ||
strncasecmp(wordStart, "Oblique", wordLength) == 0 ||
strncasecmp(wordStart, "Italic", wordLength) == 0 ||
strncasecmp(wordStart, "Thin", wordLength) == 0 ||
strncasecmp(wordStart, "Light", wordLength) == 0 ||
strncasecmp(wordStart, "Bold", wordLength) == 0 ||
strncasecmp(wordStart, "Black", wordLength) == 0 ||
strncasecmp(wordStart, "Condensed", wordLength) == 0 ||
strncasecmp(wordStart, "Expanded", wordLength) == 0
) {
if(alternativeBuffer == NULL)
{
alternativeBuffer = (FFstrbuf*) ffListAdd(&font->styles);
ffStrbufInit(alternativeBuffer);
}
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
if(
strncasecmp(wordStart, "Ultra ", 6) == 0 ||
strncasecmp(wordStart, "Extra ", 6) == 0 ||
strncasecmp(wordStart, "Semi ", 5) == 0 ||
strncasecmp(wordStart, "Demi ", 5) == 0
) {
fontPangoParseWord(data, font, alternativeBuffer);
}
return;
}
if(alternativeBuffer != NULL)
{
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
return;
}
if(font->name.length > 0)
ffStrbufAppendC(&font->name, ' ');
ffStrbufAppendNS(&font->name, wordLength, wordStart);
}
void ffFontInitPango(FFfont* font, const char* data)
{
ffFontInit(font);
while(*data != '\0' && *data != '`' && *data != '\\')
fontPangoParseWord(&data, font, NULL);
fontInitPretty(font);
}
void ffFontInitValues(FFfont* font, const char* name, const char* size)
{
ffFontInit(font);
ffStrbufAppendS(&font->name, name);
ffStrbufTrim(&font->name, '"');
ffStrbufAppendS(&font->size, size);
fontInitPretty(font);
}
void ffFontInitWithSpace(FFfont* font, const char* rawName)
{
const char* pspace = strrchr(rawName, ' ');
if(pspace == NULL)
{
ffFontInitCopy(font, rawName);
return;
}
ffFontInit(font);
ffStrbufAppendNS(&font->name, (uint32_t)(pspace - rawName), rawName);
ffStrbufAppendS(&font->size, pspace + 1);
fontInitPretty(font);
}
void ffFontDestroy(FFfont* font)
{
ffStrbufDestroy(&font->pretty);
ffStrbufDestroy(&font->name);
ffStrbufDestroy(&font->size);
FF_LIST_FOR_EACH(FFstrbuf, str, font->styles)
ffStrbufDestroy(str);
ffListDestroy(&font->styles);
}
+5 -2
View File
@@ -1,7 +1,7 @@
#pragma once
#include "util/FFstrbuf.h"
#include "util/FFlist.h"
#include "common/FFstrbuf.h"
#include "common/FFlist.h"
typedef struct FFfont
{
@@ -15,6 +15,9 @@ void ffFontInit(FFfont* font);
void ffFontInitQt(FFfont* font, const char* data);
void ffFontInitPango(FFfont* font, const char* data);
void ffFontInitValues(FFfont* font, const char* name, const char* size);
void ffFontInitXlfd(FFfont* font, const char* xlfd);
void ffFontInitXft(FFfont* font, const char* xft);
void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf* style);
void ffFontInitWithSpace(FFfont* font, const char* rawName);
void ffFontDestroy(FFfont* font);
+1 -1
View File
@@ -1,6 +1,6 @@
#pragma once
#include "util/FFstrbuf.h"
#include "common/FFstrbuf.h"
typedef enum __attribute__((__packed__)) FFformatArgType
{
+2
View File
@@ -1,3 +1,5 @@
#pragma once
#include "fastfetch.h"
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result);
@@ -1,3 +1,3 @@
#include "util/FFstrbuf.h"
#include "common/FFstrbuf.h"
bool ffGetFileVersion(const char* filePath, FFstrbuf* version);
@@ -1,6 +1,6 @@
#include "FFPlatform_private.h"
#include "util/stringUtils.h"
#include "common/io/io.h"
#include "common/stringUtils.h"
#include "common/io.h"
#include "detection/version/version.h"
void ffPlatformInit(FFPlatform* platform)
@@ -16,6 +16,10 @@ void ffPlatformInit(FFPlatform* platform)
ffStrbufInit(&platform->hostName);
ffStrbufInit(&platform->userShell);
#ifdef _WIN32
ffStrbufInit(&platform->sid);
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
ffStrbufInit(&info->name);
@@ -51,12 +55,15 @@ void ffPlatformDestroy(FFPlatform* platform)
ffStrbufDestroy(&platform->userShell);
ffStrbufDestroy(&platform->fullUserName);
#ifdef _WIN32
ffStrbufDestroy(&platform->sid);
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
ffStrbufDestroy(&info->architecture);
ffStrbufDestroy(&info->name);
ffStrbufDestroy(&info->release);
ffStrbufDestroy(&info->version);
ffStrbufDestroy(&info->displayVersion);
}
void ffPlatformPathAddAbsolute(FFlist* dirs, const char* path)
@@ -1,6 +1,6 @@
#pragma once
#include "FFPlatform.h"
#include "common/FFPlatform.h"
void ffPlatformInitImpl(FFPlatform* platform);
@@ -1,7 +1,8 @@
#include "FFPlatform_private.h"
#include "util/stringUtils.h"
#include "common/FFstrbuf.h"
#include "common/stringUtils.h"
#include "common/io.h"
#include "fastfetch_config.h"
#include "common/io/io.h"
#include <unistd.h>
#include <pwd.h>
@@ -21,21 +22,21 @@
static void getExePath(FFPlatform* platform)
{
char exePath[PATH_MAX + 1];
char exePath[PATH_MAX];
#if defined(__linux__) || defined (__GNU__)
ssize_t exePathLen = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
if (exePathLen >= 0)
exePath[exePathLen] = '\0';
#elif defined(__APPLE__)
int exePathLen = proc_pidpath((int) getpid(), exePath, sizeof(exePath));
int exePathLen = proc_pidpath((pid_t) platform->pid, exePath, sizeof(exePath));
#elif defined(__FreeBSD__) || defined(__NetBSD__)
size_t exePathLen = sizeof(exePath);
if(sysctl(
(int[]){CTL_KERN,
#ifdef __FreeBSD__
KERN_PROC, KERN_PROC_PATHNAME, (int) getpid()
KERN_PROC, KERN_PROC_PATHNAME, (pid_t) platform->pid
#else
KERN_PROC_ARGS, (int) getpid(), KERN_PROC_PATHNAME
KERN_PROC_ARGS, platform->pid, KERN_PROC_PATHNAME
#endif
}, 4,
exePath, &exePathLen,
@@ -57,7 +58,7 @@ static void getExePath(FFPlatform* platform)
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
if (info.type == B_APP_IMAGE) {
exePathLen = strlcpy(exePath, info.name, PATH_MAX);
exePathLen = strlcpy(exePath, info.name, sizeof(exePath));
break;
}
}
@@ -176,13 +177,16 @@ static void getDataDirs(FFPlatform* platform)
static void getUserName(FFPlatform* platform, const struct passwd* pwd)
{
const char* user = getenv("USER");
if(!ffStrSet(user) && pwd)
user = pwd->pw_name;
ffStrbufAppendS(&platform->userName, user);
if (pwd) ffStrbufAppendS(&platform->fullUserName, pwd->pw_gecos);
if (pwd)
{
ffStrbufSetS(&platform->userName, pwd->pw_name);
ffStrbufSetS(&platform->fullUserName, pwd->pw_gecos);
ffStrbufTrimSpace(&platform->fullUserName);
}
else
{
ffStrbufSetS(&platform->userName, getenv("USER"));
}
}
static void getHostName(FFPlatform* platform, const struct utsname* uts)
@@ -211,7 +215,6 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts)
else
#endif
ffStrbufAppendS(&info->architecture, uts->machine);
ffStrbufInit(&info->displayVersion);
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
size_t length = sizeof(info->pageSize);
@@ -223,7 +226,9 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts)
void ffPlatformInitImpl(FFPlatform* platform)
{
struct passwd* pwd = getpwuid(getuid());
platform->pid = (uint32_t) getpid();
platform->uid = getuid();
struct passwd* pwd = getpwuid(platform->uid);
struct utsname uts;
if(uname(&uts) < 0)
@@ -1,13 +1,15 @@
#include "FFPlatform_private.h"
#include "common/io/io.h"
#include "common/io.h"
#include "common/library.h"
#include "util/stringUtils.h"
#include "util/windows/unicode.h"
#include "util/windows/registry.h"
#include "util/windows/nt.h"
#include "common/mallocHelper.h"
#include "common/stringUtils.h"
#include "common/windows/unicode.h"
#include "common/windows/registry.h"
#include "common/windows/nt.h"
#include <Windows.h>
#include <windows.h>
#include <shlobj.h>
#include <sddl.h>
#define SECURITY_WIN32 1 // For secext.h
#include <secext.h>
@@ -16,7 +18,7 @@ static void getExePath(FFPlatform* platform)
{
wchar_t exePathW[MAX_PATH];
DWORD exePathWLen = GetModuleFileNameW(NULL, exePathW, MAX_PATH);
if (exePathWLen == 0 && exePathWLen >= MAX_PATH) return;
if (exePathWLen == 0 || exePathWLen >= MAX_PATH) return;
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(exePathW, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hPath != INVALID_HANDLE_VALUE)
@@ -70,15 +72,15 @@ static void getCacheDir(FFPlatform* platform)
static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId)
{
PWSTR pPath = NULL;
if(SUCCEEDED(SHGetKnownFolderPath(folderId, 0, NULL, &pPath)))
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, NULL, &pPath)))
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateWS(pPath);
CoTaskMemFree(pPath);
ffStrbufReplaceAllC(&buffer, '\\', '/');
ffStrbufEnsureEndsWithC(&buffer, '/');
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
}
CoTaskMemFree(pPath);
}
static void platformPathAddEnvSuffix(FFlist* dirs, const char* env, const char* suffix)
@@ -136,47 +138,72 @@ static void getDataDirs(FFPlatform* platform)
static void getUserName(FFPlatform* platform)
{
const char* userName = getenv("USERNAME");
if (ffStrSet(userName))
ffStrbufSetS(&platform->userName, userName);
else
{
wchar_t buffer[256];
DWORD len = ARRAY_SIZE(buffer);
if(GetUserNameW(buffer, &len))
ffStrbufSetWS(&platform->userName, buffer);
}
wchar_t buffer[256];
DWORD len = ARRAY_SIZE(buffer);
if (GetUserNameExW(NameDisplay, buffer, &len))
DWORD size = ARRAY_SIZE(buffer);
if (GetUserNameExW(NameDisplay, buffer, &size))
ffStrbufSetWS(&platform->fullUserName, buffer);
size = ARRAY_SIZE(buffer);
if (GetUserNameW(buffer, &size)) // GetUserNameExW(10002)?
{
ffStrbufSetWS(&platform->userName, buffer);
size = 0;
DWORD refDomainSize = 0;
SID_NAME_USE sidNameUse = SidTypeUnknown;
LookupAccountNameW(NULL, buffer, NULL, &size, NULL, &refDomainSize, &sidNameUse);
if (size > 0)
{
FF_AUTO_FREE PSID sid = (PSID) malloc(size);
FF_AUTO_FREE LPWSTR refDomain = (LPWSTR) malloc(refDomainSize * sizeof(wchar_t));
if (LookupAccountNameW(NULL, buffer, sid, &size, refDomain, &refDomainSize, &sidNameUse))
{
LPWSTR sidString;
if (ConvertSidToStringSidW(sid, &sidString))
{
ffStrbufSetWS(&platform->sid, sidString);
LocalFree(sidString);
}
}
}
}
else
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
}
static void getHostName(FFPlatform* platform)
{
wchar_t buffer[128];
wchar_t buffer[256];
DWORD len = ARRAY_SIZE(buffer);
if(GetComputerNameExW(ComputerNameDnsHostname, buffer, &len))
ffStrbufSetWS(&platform->hostName, buffer);
if (GetComputerNameExW(ComputerNameDnsHostname, buffer, &len) && len > 0)
ffStrbufSetNWS(&platform->hostName, len, buffer);
else
{
len = ARRAY_SIZE(buffer);
if (GetComputerNameExW(ComputerNameNetBIOS, buffer, &len) && len > 0)
ffStrbufSetNWS(&platform->hostName, len, buffer);
}
}
static void getUserShell(FFPlatform* platform)
{
// Works in MSYS2
ffStrbufAppendS(&platform->userShell, getenv("SHELL"));
ffStrbufReplaceAllC(&platform->userShell, '\\', '/');
const char* userShell = getenv("SHELL");
if (userShell)
{
ffStrbufAppendS(&platform->userShell, userShell);
ffStrbufReplaceAllC(&platform->userShell, '\\', '/');
}
}
static void detectWine(FFstrbuf* buf)
static const char* detectWine(void)
{
const char * __cdecl wine_get_version(void);
HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
if (!hntdll) return;
if (!hntdll) return NULL;
FF_LIBRARY_LOAD_SYMBOL_LAZY(hntdll, wine_get_version);
if (!ffwine_get_version) return;
ffStrbufAppendS(buf, buf->length ? " - wine " : "wine ");
ffStrbufAppendS(buf, ffwine_get_version());
if (!ffwine_get_version) return NULL;
return ffwine_get_version();
}
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
@@ -199,29 +226,25 @@ static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
(unsigned) osVersion.dwBuildNumber,
(unsigned) ubr);
ffStrbufInit(&info->displayVersion);
if(!ffRegReadStrbuf(hKey, L"DisplayVersion", &info->displayVersion, NULL))
{
if (osVersion.szCSDVersion[0])
ffStrbufSetWS(&info->displayVersion, osVersion.szCSDVersion);
else
ffRegReadStrbuf(hKey, L"ReleaseId", &info->displayVersion, NULL); // For old Windows 10
}
detectWine(&info->displayVersion);
ffRegReadStrbuf(hKey, L"BuildLabEx", &info->version, NULL);
switch (osVersion.dwPlatformId)
const char* wineVersion = detectWine();
if (wineVersion)
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
else
{
case VER_PLATFORM_WIN32s:
ffStrbufSetStatic(&info->name, "WIN32s");
break;
case VER_PLATFORM_WIN32_WINDOWS:
ffStrbufSetStatic(&info->name, "WIN32_WINDOWS");
break;
case VER_PLATFORM_WIN32_NT:
ffStrbufSetStatic(&info->name, "WIN32_NT");
break;
switch (osVersion.dwPlatformId)
{
case VER_PLATFORM_WIN32s:
ffStrbufSetStatic(&info->name, "WIN32s");
break;
case VER_PLATFORM_WIN32_WINDOWS:
ffStrbufSetStatic(&info->name, "WIN32_WINDOWS");
break;
case VER_PLATFORM_WIN32_NT:
ffStrbufSetStatic(&info->name, "WIN32_NT");
break;
}
}
}
@@ -284,6 +307,7 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
void ffPlatformInitImpl(FFPlatform* platform)
{
platform->pid = (uint32_t) GetCurrentProcessId();
getExePath(platform);
getHomeDir(platform);
getCacheDir(platform);
@@ -1,4 +1,4 @@
#include "FFlist.h"
#include "common/FFlist.h"
#include <stdlib.h>
#include <string.h>
@@ -1,4 +1,5 @@
#include "FFstrbuf.h"
#include "common/FFstrbuf.h"
#include "common/mallocHelper.h"
#include <ctype.h>
#include <inttypes.h>
@@ -21,11 +22,27 @@ void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments)
{
assert(format != NULL);
int len = vasprintf(&strbuf->chars, format, arguments);
char* buffer = NULL;
int len = vasprintf(&buffer, format, arguments);
assert(len >= 0);
strbuf->allocated = (uint32_t)(len + 1);
strbuf->length = (uint32_t)len;
ffStrbufInitMoveNS(strbuf, (uint32_t)len, buffer);
}
// Takes ownership of `heapStr`. The caller must not free `heapStr` after calling this
// function; the memory will be managed and freed via the associated FFstrbuf.
void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr)
{
assert(heapStr != NULL);
strbuf->length = length;
size_t allocSize = ffMallocUsableSize(heapStr);
if (allocSize == 0)
allocSize = length + 1;
else if (allocSize > UINT32_MAX)
allocSize = UINT32_MAX;
strbuf->allocated = (uint32_t) allocSize;
strbuf->chars = heapStr;
}
void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
@@ -55,6 +72,7 @@ void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
strbuf->allocated = allocate;
}
// Ensure that at least `free` bytes are available in the buffer besides the current length
// for an empty buffer, free + 1 length memory will be allocated(+1 for the NUL)
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free)
{
@@ -148,7 +166,7 @@ void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments)
uint32_t free = ffStrbufGetFree(strbuf);
int written = vsnprintf(strbuf->chars + strbuf->length, strbuf->allocated > 0 ? free + 1 : 0, format, arguments);
if(written > 0 && strbuf->length + (uint32_t) written > free)
if(written > 0 && (uint32_t) written > free)
{
ffStrbufEnsureFree(strbuf, (uint32_t) written);
written = vsnprintf(strbuf->chars + strbuf->length, (uint32_t) written + 1, format, copy);
@@ -165,7 +183,7 @@ const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char unti
if(value == NULL)
return NULL;
char* end = strchr(value, until);
const char* end = strchr(value, until);
if(end == NULL)
ffStrbufAppendS(strbuf, value);
else
@@ -220,6 +238,55 @@ void ffStrbufPrependC(FFstrbuf* strbuf, char c)
strbuf->length += 1;
}
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value)
{
assert(strbuf != NULL);
if (length == 0)
{
ffStrbufClear(strbuf);
return;
}
assert(value != NULL);
if (strbuf->allocated < length + 1)
{
if (strbuf->allocated > 0)
free(strbuf->chars);
strbuf->allocated = length + 1;
strbuf->chars = malloc(sizeof(char) * strbuf->allocated);
}
memcpy(strbuf->chars, value, length);
strbuf->length = length;
strbuf->chars[length] = '\0';
}
void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value)
{
assert(value && value != strbuf);
if (value->length == 0)
{
ffStrbufClear(strbuf);
return;
}
if (value->allocated == 0) // static string
{
if (strbuf->allocated != 0)
{
free(strbuf->chars);
strbuf->allocated = 0;
}
strbuf->chars = value->chars;
strbuf->length = value->length;
return;
}
ffStrbufSetNS(strbuf, value->length, value->chars);
}
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c)
{
if(strbuf->length == 0)
@@ -381,7 +448,15 @@ void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace)
return;
ffStrbufEnsureFree(strbuf, 0);
for (char *current_pos = strchr(strbuf->chars, find); current_pos; current_pos = strchr(current_pos + 1, find))
for (
char *current_pos = memchr(strbuf->chars, find, strbuf->length);
current_pos;
current_pos = memchr(
current_pos + 1,
find,
strbuf->length - (uint32_t)(current_pos + 1 - strbuf->chars)
)
)
*current_pos = replace;
}
@@ -648,19 +723,7 @@ void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c)
strbuf->length += num;
}
/**
* @brief Read a line from a FFstrbuf.
*
* @details Behaves like getline(3) but reads from a FFstrbuf.
*
* @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line.
* Can be NULL for the first call.
* @param[in,out] n The pointer to the size of the buffer of lineptr.
* @param[in] buffer The buffer to read from. The buffer must not be a string literal.
*
* @return true if a line has been read, false if the end of the buffer has been reached.
*/
bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer)
{
assert(lineptr && n && buffer);
assert(buffer->allocated > 0 || (buffer->allocated == 0 && buffer->length == 0));
@@ -674,14 +737,14 @@ bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
*lineptr += *n;
if (*lineptr >= pBufferEnd) // non-empty last line
return false;
**lineptr = '\n';
**lineptr = delimiter;
++*lineptr;
}
if (*lineptr >= pBufferEnd) // empty last line
return false;
size_t remaining = (size_t) (pBufferEnd - *lineptr);
char* ending = memchr(*lineptr, '\n', remaining);
char* ending = memchr(*lineptr, delimiter, remaining);
if (ending)
{
*n = (size_t) (ending - *lineptr);
@@ -692,9 +755,7 @@ bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
return true;
}
/// @brief Restore the end of a line that was modified by ffStrbufGetline.
/// @warning This function should be called before breaking an ffStrbufGetline loop.
void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer)
void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer)
{
assert(buffer && lineptr && n);
assert(buffer->allocated > 0 || (buffer->allocated == 0 && buffer->length == 0));
@@ -705,7 +766,7 @@ void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer)
*lineptr += *n;
if (*lineptr < buffer->chars + buffer->length)
**lineptr = '\n';
**lineptr = delimiter;
}
bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf)
@@ -1,4 +1,4 @@
#include "base64.h"
#include "common/base64.h"
// https://github.com/kostya/benchmarks/blob/master/base64/test-nolib.c#L145
void ffBase64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output)
@@ -1,7 +1,7 @@
#include "binary.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include "util/mallocHelper.h"
#include "common/binary.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/mallocHelper.h"
#include <stdlib.h>
#include <string.h>
@@ -1,10 +1,10 @@
#include "binary.h"
#include "common/binary.h"
#if defined(FF_HAVE_ELF) || defined(__sun) || (defined(__FreeBSD__) && !defined(__DragonFly__)) || defined(__OpenBSD__) || defined(__NetBSD__)
#include "common/io/io.h"
#include "common/io.h"
#include "common/library.h"
#include "util/stringUtils.h"
#include "common/stringUtils.h"
#include <libelf.h> // #1254
#include <fcntl.h>
@@ -42,7 +42,7 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
if (!elfData.inited)
{
elfData.inited = true;
FF_LIBRARY_LOAD(libelf, "dlopen libelf" FF_LIBRARY_EXTENSION " failed", "libelf" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_MESSAGE(libelf, "libelf" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_version)
if (elfData.ffelf_version(EV_CURRENT) == EV_NONE) return "elf_version() failed";
@@ -1,7 +1,7 @@
#include "binary.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include "util/mallocHelper.h"
#include "common/binary.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/mallocHelper.h"
#include <windows.h>
#include <imagehlp.h>
@@ -1,11 +1,11 @@
#include "commandoption.h"
#include "common/commandoption.h"
#include "common/color.h"
#include "common/printing.h"
#include "common/time.h"
#include "common/jsonconfig.h"
#include "common/stringUtils.h"
#include "fastfetch_datatext.h"
#include "modules/modules.h"
#include "util/stringUtils.h"
#include <ctype.h>
#include <inttypes.h>
@@ -61,7 +61,7 @@ bool ffParseModuleOptions(const char* key, const char* value)
}
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 ? "\"" : "");
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ?: "true", value ? "\"" : "");
fputs(" See <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration> for more information.\n", stderr);
exit(477);
}
@@ -71,40 +71,66 @@ bool ffParseModuleOptions(const char* key, const char* value)
void ffPrepareCommandOption(FFdata* data)
{
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME, ':'))
ffPrepareCPUUsage();
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME, ':'))
char* moduleType = NULL;
size_t moduleLen = 0;
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
{
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
ffPrepareDiskIO(&options);
}
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (moduleLen == strlen(moduleNameConstant) \
&& ffStrEqualsIgnCase(moduleType, moduleNameConstant) \
&& !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
ffInitNetIOOptions(&options);
ffPrepareNetIO(&options);
}
switch (moduleType[0])
{
case 'C': case 'c':
FF_IF_MODULE_MATCH(FF_CPUUSAGE_MODULE_NAME)
ffPrepareCPUUsage();
break;
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
case 'D': case 'd':
FF_IF_MODULE_MATCH(FF_DISKIO_MODULE_NAME)
{
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
ffPrepareDiskIO(&options);
}
break;
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
case 'N': case 'n':
FF_IF_MODULE_MATCH(FF_NETIO_MODULE_NAME)
{
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
ffInitNetIOOptions(&options);
ffPrepareNetIO(&options);
}
break;
case 'P': case 'p':
FF_IF_MODULE_MATCH(FF_PUBLICIP_MODULE_NAME)
{
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
break;
case 'W': case 'w':
FF_IF_MODULE_MATCH(FF_WEATHER_MODULE_NAME)
{
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
}
break;
}
#undef FF_IF_MODULE_MATCH
}
}
static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
static void genJsonConfig(FFdata* data, FFModuleBaseInfo* baseInfo, void* options)
{
yyjson_mut_doc* doc = data->resultDoc;
yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules");
if (!modules)
modules = yyjson_mut_obj_add_arr(doc, doc->root, "modules");
@@ -112,7 +138,7 @@ static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_
FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
ffStrbufLowerCase(&type);
if (instance.state.fullConfig)
if (data->docType == FF_RESULT_DOC_TYPE_CONFIG_FULL)
{
yyjson_mut_val* module = yyjson_mut_obj(doc);
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
@@ -131,8 +157,9 @@ static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_
}
}
static void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
static void genJsonResult(FFdata* data, FFModuleBaseInfo* baseInfo, void* options)
{
yyjson_mut_doc* doc = data->resultDoc;
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)
@@ -142,9 +169,9 @@ static void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_
}
static void parseStructureCommand(
FFdata* data,
const char* line,
void (*fn)(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* jsonDoc),
yyjson_mut_doc* jsonDoc
void (*fn)(FFdata*, FFModuleBaseInfo* baseInfo, void* options)
)
{
if(ffCharIsEnglishAlphabet(line[0]))
@@ -156,8 +183,8 @@ static void parseStructureCommand(
{
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
baseInfo->initOptions(optionBuf);
if (__builtin_expect(jsonDoc != NULL, false))
fn(baseInfo, optionBuf, jsonDoc);
if (__builtin_expect(data->resultDoc != NULL, false))
fn(data, baseInfo, optionBuf);
else
baseInfo->printModule(optionBuf);
baseInfo->destroyOptions(optionBuf);
@@ -169,30 +196,32 @@ static void parseStructureCommand(
ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
}
void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
void ffPrintCommandOption(FFdata* data)
{
//Parse the structure and call the modules
int32_t thres = instance.config.display.stat;
uint32_t startIndex = 0;
while (startIndex < data->structure.length)
char* moduleType = NULL;
size_t moduleLen = 0;
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
{
uint32_t colonIndex = ffStrbufNextIndexC(&data->structure, startIndex, ':');
data->structure.chars[colonIndex] = '\0';
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':'))
continue;
double ms = 0;
if(thres >= 0)
ms = ffTimeGetTick();
parseStructureCommand(data->structure.chars + startIndex, genJsonResult, jsonDoc);
parseStructureCommand(data, moduleType, genJsonResult);
if(thres >= 0)
{
ms = ffTimeGetTick() - ms;
if (jsonDoc)
if (data->resultDoc)
{
yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(jsonDoc->root);
yyjson_mut_obj_add_real(jsonDoc, moduleJson, "stat", ms);
yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(data->resultDoc->root);
yyjson_mut_obj_add_real(data->resultDoc, moduleJson, "stat", ms);
}
else
{
@@ -205,28 +234,24 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
}
#if defined(_WIN32)
if (!jsonDoc && !instance.config.display.noBuffer) fflush(stdout);
if (!data->resultDoc && !instance.config.display.noBuffer) fflush(stdout);
#endif
startIndex = colonIndex + 1;
}
}
void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc)
void ffMigrateCommandOptionToJsonc(FFdata* data)
{
//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
//Parse the structure and call the modules
uint32_t startIndex = 0;
while (startIndex < data->structure.length)
char* moduleType = NULL;
size_t moduleLen = 0;
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
{
uint32_t colonIndex = ffStrbufNextIndexC(&data->structure, startIndex, ':');
data->structure.chars[colonIndex] = '\0';
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':'))
continue;
parseStructureCommand(data->structure.chars + startIndex, genJsonConfig, jsonDoc);
startIndex = colonIndex + 1;
parseStructureCommand(data, moduleType, genJsonConfig);
}
}
+2 -2
View File
@@ -1,9 +1,9 @@
#include "dbus.h"
#include "common/dbus.h"
#ifdef FF_HAVE_DBUS
#include "common/thread.h"
#include "util/stringUtils.h"
#include "common/stringUtils.h"
static bool loadLibSymbols(FFDBusLibrary* lib)
{
@@ -1,4 +1,4 @@
#include "debug.h"
#include "common/debug.h"
#include <windows.h>
@@ -1,4 +1,4 @@
#include "duration.h"
#include "common/duration.h"
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result)
{
@@ -1,4 +1,4 @@
#include "edidHelper.h"
#include "common/edidHelper.h"
void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height)
{
+520
View File
@@ -0,0 +1,520 @@
#include "fastfetch.h"
#include "common/FFlist.h"
#include "common/FFstrbuf.h"
#include "common/stringUtils.h"
#include "common/font.h"
#include <string.h>
#include <ctype.h>
void ffFontInit(FFfont* font)
{
// Ensure no memory allocates
ffStrbufInit(&font->pretty);
ffStrbufInit(&font->name);
ffStrbufInit(&font->size);
ffListInit(&font->styles, sizeof(FFstrbuf));
}
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
{
if(value == NULL || length == 0)
return;
ffStrbufEnsureFree(strbuf, length);
for(uint32_t i = 0; i < length; i++)
{
if(value[i] != exclude)
strbuf->chars[strbuf->length++] = value[i];
}
strbuf->chars[strbuf->length] = '\0';
}
static void fontInitPretty(FFfont* font)
{
ffStrbufAppend(&font->pretty, &font->name);
if(font->size.length == 0 && font->styles.length == 0)
return;
else if(font->pretty.length == 0)
ffStrbufAppendS(&font->pretty, "default");
ffStrbufAppendS(&font->pretty, " (");
if(font->size.length > 0)
{
ffStrbufAppend(&font->pretty, &font->size);
if (!ffStrbufEndsWithS(&font->size, "pt") && !ffStrbufEndsWithS(&font->size, "px"))
ffStrbufAppendS(&font->pretty, "pt");
if(font->styles.length > 0)
ffStrbufAppendS(&font->pretty, ", ");
}
for(uint32_t i = 0; i < font->styles.length; i++)
{
ffStrbufAppend(&font->pretty, FF_LIST_GET(FFstrbuf, font->styles, i));
if(i < font->styles.length - 1)
ffStrbufAppendS(&font->pretty, ", ");
}
ffStrbufAppendC(&font->pretty, ')');
}
void ffFontInitQt(FFfont* font, const char* data)
{
ffFontInit(font);
//See https://doc.qt.io/qt-5/qfont.html#toString
//Family
data = ffStrbufAppendSUntilC(&font->name, data, ',');
ffStrbufTrim(&font->name, ' ');
if (!data) goto exit;
data++;
//Size
data = ffStrbufAppendSUntilC(&font->size, data, ',');
ffStrbufTrim(&font->size, ' ');
if (!data) goto exit;
data++;
//Style
data = strrchr(data, ',');
if (!data) goto exit;
data++;
if (isalpha(*data))
{
do
{
FFstrbuf* style = (FFstrbuf*) ffListAdd(&font->styles);
ffStrbufInit(style);
data = ffStrbufAppendSUntilC(style, data, ' ');
if (data) data++;
} while (data);
}
exit:
fontInitPretty(font);
}
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
{
while(**data == ' ' || **data == '\t' || **data == ',')
++(*data);
const char* wordStart = *data;
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
++(*data);
uint32_t wordLength = (uint32_t) (*data - wordStart);
if(wordLength == 0)
return;
if(**data == '\0' || **data == '`' || **data == '\\')
{
ffStrbufAppendNS(&font->size, wordLength, wordStart);
if(ffStrbufEndsWithS(&font->size, "px"))
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
double dummy;
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
return;
ffStrbufClear(&font->size);
}
if(
ffStrStartsWithIgnCase(wordStart, "Ultra") ||
ffStrStartsWithIgnCase(wordStart, "Extra") ||
ffStrStartsWithIgnCase(wordStart, "Semi") ||
ffStrStartsWithIgnCase(wordStart, "Demi") ||
ffStrStartsWithIgnCase(wordStart, "Normal") ||
ffStrStartsWithIgnCase(wordStart, "Roman") ||
ffStrStartsWithIgnCase(wordStart, "Oblique") ||
ffStrStartsWithIgnCase(wordStart, "Italic") ||
ffStrStartsWithIgnCase(wordStart, "Thin") ||
ffStrStartsWithIgnCase(wordStart, "Light") ||
ffStrStartsWithIgnCase(wordStart, "Bold") ||
ffStrStartsWithIgnCase(wordStart, "Black") ||
ffStrStartsWithIgnCase(wordStart, "Condensed") ||
ffStrStartsWithIgnCase(wordStart, "Expanded")
) {
if(alternativeBuffer == NULL)
{
alternativeBuffer = (FFstrbuf*) ffListAdd(&font->styles);
ffStrbufInit(alternativeBuffer);
}
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
if(
ffStrStartsWithIgnCase(wordStart, "Ultra ") ||
ffStrStartsWithIgnCase(wordStart, "Extra ") ||
ffStrStartsWithIgnCase(wordStart, "Semi ") ||
ffStrStartsWithIgnCase(wordStart, "Demi ")
) {
fontPangoParseWord(data, font, alternativeBuffer);
}
return;
}
if(alternativeBuffer != NULL)
{
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
return;
}
if(font->name.length > 0)
ffStrbufAppendC(&font->name, ' ');
ffStrbufAppendNS(&font->name, wordLength, wordStart);
}
void ffFontInitPango(FFfont* font, const char* data)
{
ffFontInit(font);
while(*data != '\0' && *data != '`' && *data != '\\')
fontPangoParseWord(&data, font, NULL);
fontInitPretty(font);
}
void ffFontInitValues(FFfont* font, const char* name, const char* size)
{
ffFontInit(font);
ffStrbufAppendS(&font->name, name);
ffStrbufTrim(&font->name, '"');
ffStrbufAppendS(&font->size, size);
fontInitPretty(font);
}
void ffFontInitXlfd(FFfont* font, const char* xlfd)
{
assert(xlfd && *xlfd);
// https://en.wikipedia.org/wiki/X_logical_font_description
ffFontInit(font);
// XLFD: -foundry-family-weight-slant-setwidth-addstyle-pixelsize-pointsize-xres-yres-spacing-averagewidth-charsetregistry-charsetencoding
// It often starts with '-', which would create an empty first field. Skip it to align indexes.
if(*xlfd == '-')
xlfd++;
const char* pstart = xlfd;
for(int field = 0; field < 14; field++)
{
const char* pend = strchr(pstart, '-');
uint32_t length = pend ? (uint32_t)(pend - pstart) : (uint32_t) strlen(pstart);
if(length > 0)
{
if(field == 1) // family
{
ffStrbufAppendNS(&font->name, length, pstart);
}
else if(field == 7) // pointsize (decipoints, preferred)
{
// parse positive integer from substring
long deciPt = 0;
bool ok = true;
for(uint32_t i = 0; i < length; i++)
{
char c = pstart[i];
if(c < '0' || c > '9') { ok = false; break; }
deciPt = deciPt * 10 + (c - '0');
}
if(ok && deciPt > 0)
{
ffStrbufClear(&font->size);
char tmp[32];
if(deciPt % 10 == 0)
snprintf(tmp, sizeof(tmp), "%ldpt", deciPt / 10);
else
snprintf(tmp, sizeof(tmp), "%ld.%ldpt", deciPt / 10, deciPt % 10);
ffStrbufAppendS(&font->size, tmp);
}
}
else if(field == 6) // pixelsize (fallback if pointsize missing/invalid)
{
if(font->size.length == 0)
{
long px = 0;
bool ok = true;
for(uint32_t i = 0; i < length; i++)
{
char c = pstart[i];
if(c < '0' || c > '9') { ok = false; break; }
px = px * 10 + (c - '0');
}
if(ok && px > 0)
{
ffStrbufAppendNS(&font->size, length, pstart);
ffStrbufAppendS(&font->size, "px");
}
}
}
else if(field >= 2 && field <= 5) // weight/slant/setwidth/addstyle
{
// ignore "normal" (case-insensitive)
if(!(length == 6 && ffStrStartsWithIgnCase(pstart, "normal")))
{
FFstrbuf* style = (FFstrbuf*) ffListAdd(&font->styles);
ffStrbufInitNS(style, length, pstart);
}
}
}
if(!pend)
break;
pstart = pend + 1;
}
fontInitPretty(font);
}
void ffFontInitXft(FFfont* font, const char* xft)
{
assert(xft);
// https://en.wikipedia.org/wiki/Xft
// Xft/Fontconfig pattern examples:
// "DejaVu Sans Mono-10"
// "monospace:size=10:weight=bold:slant=italic"
// "Fira Code-12:style=Regular"
// Goal: extract family(name), size, and some common styles.
ffFontInit(font);
// 1) Parse "head" part before first ':' => usually "family[-size]" (may include commas)
const char* p = xft;
while(*p == ' ' || *p == '\t')
++p;
const char* headStart = p;
while(*p != '\0' && *p != ':')
++p;
const char* headEnd = p;
// trim tail spaces
while(headEnd > headStart && (headEnd[-1] == ' ' || headEnd[-1] == '\t'))
--headEnd;
// If multiple families are listed, take the first one (up to comma)
for(const char* q = headStart; q < headEnd; ++q)
{
if(*q == ',')
{
headEnd = q;
while(headEnd > headStart && (headEnd[-1] == ' ' || headEnd[-1] == '\t'))
--headEnd;
break;
}
}
// Try parse trailing "-<number>" as size, otherwise entire head is name
const char* dashPos = NULL;
const char* sizeStart = NULL;
for(const char* q = headEnd; q > headStart; )
{
--q;
if(*q == '-' && (q + 1) < headEnd && ffCharIsDigit(q[1]))
{
dashPos = q;
sizeStart = q + 1;
break;
}
}
if(dashPos)
{
bool ok = true;
bool seenDigit = false;
for(const char* q = sizeStart; q < headEnd; ++q)
{
if(ffCharIsDigit(*q))
seenDigit = true;
else if(*q == '.')
continue;
else
{
ok = false;
break;
}
}
if(ok && seenDigit)
{
const char* nameEnd = dashPos;
while(nameEnd > headStart && (nameEnd[-1] == ' ' || nameEnd[-1] == '\t'))
--nameEnd;
if(nameEnd > headStart)
ffStrbufAppendNS(&font->name, (uint32_t) (nameEnd - headStart), headStart);
if(headEnd > sizeStart)
ffStrbufAppendNS(&font->size, (uint32_t) (headEnd - sizeStart), sizeStart);
}
else
{
if(headEnd > headStart)
ffStrbufAppendNS(&font->name, (uint32_t) (headEnd - headStart), headStart);
}
}
else
{
if(headEnd > headStart)
ffStrbufAppendNS(&font->name, (uint32_t) (headEnd - headStart), headStart);
}
ffStrbufTrim(&font->name, ' ');
ffStrbufTrim(&font->name, '"');
// 2) Parse key=value fields after ':' (Fontconfig-like). Fields separated by ':'.
// Common keys: size, pixelsize, pointsize, style, weight, slant, width
while(*p == ':')
{
++p;
// key
const char* keyStart = p;
while(*p != '\0' && *p != '=' && *p != ':')
++p;
const char* keyEnd = p;
if(*p != '=')
continue; // skip tokens without '='
++p; // skip '='
// value (until next ':', allow backslash-escaping)
FF_STRBUF_AUTO_DESTROY value = ffStrbufCreate();
while(*p != '\0' && *p != ':')
{
if(*p == '\\' && p[1] != '\0')
{
++p;
ffStrbufAppendC(&value, *p);
++p;
continue;
}
ffStrbufAppendC(&value, *p);
++p;
}
ffStrbufTrim(&value, ' ');
ffStrbufTrim(&value, '"');
uint32_t keyLen = (uint32_t) (keyEnd - keyStart);
// helper: set numeric size if not set yet
const bool sizeEmpty = (font->size.length == 0);
if(value.length > 0)
{
if(
(keyLen == 4 && ffStrStartsWithIgnCase(keyStart, "size")) ||
(keyLen == 9 && ffStrStartsWithIgnCase(keyStart, "pixelsize"))
)
{
if(sizeEmpty && ffCharIsDigit(value.chars[0]))
{
ffStrbufAppend(&font->size, &value);
ffStrbufAppendS(&font->size, keyLen == 4 ? "pt" : "px");
}
}
else if(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "style"))
{
// style may contain multiple words: "Bold Italic"
const char* s = value.chars;
while(*s != '\0')
{
while(*s == ' ' || *s == '\t' || *s == ',')
++s;
const char* w = s;
while(*s != '\0' && *s != ' ' && *s != '\t' && *s != ',')
++s;
if(s > w)
{
FFstrbuf* style = FF_LIST_ADD(FFstrbuf, font->styles);
ffStrbufInitNS(style, (uint32_t) (s - w), w);
}
}
}
else if(
(keyLen == 6 && ffStrStartsWithIgnCase(keyStart, "weight")) ||
(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "slant")) ||
(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "width"))
) {
// normalize: remove '-' to align with other parsers ("Semi-Bold" -> "SemiBold")
FFstrbuf* style = FF_LIST_ADD(FFstrbuf, font->styles);
ffStrbufInit(style);
strbufAppendNSExcludingC(style, value.length, value.chars, '-');
ffStrbufTrim(style, ' ');
}
}
}
fontInitPretty(font);
}
void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf* style)
{
ffFontInit(font);
if (name) ffStrbufInitMove(&font->name, name);
if (size) ffStrbufInitMove(&font->size, size);
if (style)
{
FFstrbuf* styleBuf = FF_LIST_ADD(FFstrbuf, font->styles);
ffStrbufInitMove(styleBuf, style);
}
fontInitPretty(font);
}
void ffFontInitWithSpace(FFfont* font, const char* rawName)
{
const char* pspace = strrchr(rawName, ' ');
if(pspace == NULL)
{
ffFontInitCopy(font, rawName);
return;
}
ffFontInit(font);
ffStrbufAppendNS(&font->name, (uint32_t)(pspace - rawName), rawName);
ffStrbufAppendS(&font->size, pspace + 1);
fontInitPretty(font);
}
void ffFontDestroy(FFfont* font)
{
ffStrbufDestroy(&font->pretty);
ffStrbufDestroy(&font->name);
ffStrbufDestroy(&font->size);
FF_LIST_FOR_EACH(FFstrbuf, str, font->styles)
ffStrbufDestroy(str);
ffListDestroy(&font->styles);
}
@@ -1,8 +1,8 @@
#include "fastfetch.h"
#include "common/format.h"
#include "common/parsing.h"
#include "util/textModifier.h"
#include "util/stringUtils.h"
#include "common/textModifier.h"
#include "common/stringUtils.h"
#include <inttypes.h>
@@ -1,4 +1,4 @@
#include "frequency.h"
#include "common/frequency.h"
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result)
{
+25 -23
View File
@@ -2,9 +2,9 @@
#include "common/init.h"
#include "common/parsing.h"
#include "common/thread.h"
#include "common/textModifier.h"
#include "detection/displayserver/displayserver.h"
#include "detection/terminaltheme/terminaltheme.h"
#include "util/textModifier.h"
#include "logo/logo.h"
#include <stdlib.h>
@@ -12,7 +12,7 @@
#include <locale.h>
#ifdef _WIN32
#include <windows.h>
#include "util/windows/unicode.h"
#include "common/windows/unicode.h"
#else
#include <signal.h>
#endif
@@ -28,8 +28,7 @@ static void initState(FFstate* state)
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
@@ -48,7 +47,7 @@ static void defaultConfig(void)
void ffInitInstance(void)
{
#ifdef WIN32
#ifdef _WIN32
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
setlocale(LC_ALL, ".UTF8");
#else
@@ -74,6 +73,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
@@ -88,16 +90,12 @@ static void exitSignalHandler(FF_MAYBE_UNUSED int signal)
resetConsole();
exit(0);
}
static void chldSignalHandler(FF_MAYBE_UNUSED int signal)
{
// empty; used to interrupt the poll and read syscalls
}
#endif
void ffStart(void)
{
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe && !instance.state.resultDoc;
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe;
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe;
#ifdef _WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
@@ -117,11 +115,14 @@ void ffStart(void)
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
sigaction(SIGCHLD, &(struct sigaction) { .sa_handler = chldSignalHandler }, NULL);
sigset_t newmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &newmask, NULL);
#endif
//reset everything to default before we start printing
if(!instance.config.display.pipe && !instance.state.resultDoc)
if(!instance.config.display.pipe)
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
if(ffHideCursor)
@@ -130,14 +131,15 @@ void ffStart(void)
if(ffDisableLinewrap)
fputs("\033[?7l", stdout);
ffLogoPrint();
if(instance.state.dynamicInterval > 0)
{
fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer
fflush(stdout);
}
}
void ffFinish(void)
{
if(instance.config.logo.printRemaining)
ffLogoPrintRemaining();
resetConsole();
}
@@ -151,9 +153,6 @@ static void destroyConfig(void)
static void destroyState(void)
{
ffPlatformDestroy(&instance.state.platform);
yyjson_doc_free(instance.state.configDoc);
yyjson_mut_doc_free(instance.state.resultDoc);
ffStrbufDestroy(&instance.state.genConfigPath);
}
void ffDestroyInstance(void)
@@ -226,9 +225,6 @@ void ffListFeatures(void)
#if FF_HAVE_FREETYPE
"freetype\n"
#endif
#if FF_HAVE_PCIACCESS
"libpciaccess\n"
#endif
#if FF_HAVE_PULSE
"libpulse\n"
#endif
@@ -256,6 +252,12 @@ void ffListFeatures(void)
#if FF_HAVE_EMBEDDED_PCIIDS
"Embedded pciids\n"
#endif
#if FF_WIN7_COMPAT
"Windows 7 Compatibility\n"
#endif
#if FF_APPLE_MEMSIZE_USABLE
"Apple memsize_usable\n"
#endif
""
, stdout);
}
@@ -1,6 +1,6 @@
#include "io.h"
#include "common/io.h"
#include "fastfetch.h"
#include "util/stringUtils.h"
#include "common/stringUtils.h"
#include "common/time.h"
#include <fcntl.h>
@@ -15,18 +15,15 @@
#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)
{
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
char *token = NULL;
const char *token = NULL;
while((token = strchr(fileName, '/')) != NULL)
{
ffStrbufAppendNS(&path, (uint32_t)(token - fileName + 1), 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);
@@ -367,3 +371,8 @@ FFNativeFD ffGetNullFD(void)
hNullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
return hNullFile;
}
bool ffRemoveFile(const char* fileName)
{
return unlink(fileName) == 0;
}
@@ -1,10 +1,10 @@
#include "io.h"
#include "common/io.h"
#include "fastfetch.h"
#include "util/stringUtils.h"
#include "common/stringUtils.h"
#include <windows.h>
#include "common/windows/nt.h"
#include <ntstatus.h>
#include <winternl.h>
static void createSubfolders(const char* fileName)
{
@@ -102,31 +102,48 @@ bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
return ffAppendFDBuffer(handle, buffer);
}
HANDLE openat(HANDLE dfd, const char* fileName, bool directory)
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory)
{
NTSTATUS ret;
UNICODE_STRING fileNameW;
ret = RtlAnsiStringToUnicodeString(&fileNameW, &(ANSI_STRING) {
.Length = (USHORT) strlen(fileName),
.Buffer = (PCHAR) fileName
}, TRUE);
if (!NT_SUCCESS(ret)) return INVALID_HANDLE_VALUE;
assert(fileNameLen <= 0x7FFF);
FF_AUTO_CLOSE_FD HANDLE hFile;
HANDLE hFile;
IO_STATUS_BLOCK iosb = {};
ret = NtOpenFile(&hFile, FILE_READ_DATA | SYNCHRONIZE, &(OBJECT_ATTRIBUTES) {
.Length = sizeof(OBJECT_ATTRIBUTES),
.RootDirectory = dfd,
.ObjectName = &fileNameW,
}, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT | (directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE));
RtlFreeUnicodeString(&fileNameW);
if(!NT_SUCCESS(ret) || iosb.Information != FILE_OPENED)
if(!NT_SUCCESS(NtOpenFile(&hFile,
(directory ? FILE_LIST_DIRECTORY | FILE_TRAVERSE : FILE_READ_DATA | FILE_READ_EA) | FILE_READ_ATTRIBUTES | SYNCHRONIZE, &(OBJECT_ATTRIBUTES) {
.Length = sizeof(OBJECT_ATTRIBUTES),
.RootDirectory = dfd,
.ObjectName = &(UNICODE_STRING) {
.Buffer = (PWSTR) fileName,
.Length = fileNameLen * (USHORT) sizeof(wchar_t),
.MaximumLength = (fileNameLen + 1) * (USHORT) sizeof(wchar_t),
},
.Attributes = OBJ_CASE_INSENSITIVE,
},
&iosb,
FILE_SHARE_READ | (directory ? FILE_SHARE_WRITE | FILE_SHARE_DELETE : 0),
FILE_SYNCHRONOUS_IO_NONALERT | (directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE)
)))
return INVALID_HANDLE_VALUE;
return hFile;
}
HANDLE openat(HANDLE dfd, const char* fileName, bool directory)
{
wchar_t fileNameW[MAX_PATH];
int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fileName, -1, fileNameW, ARRAY_SIZE(fileNameW));
if (len == 0) return INVALID_HANDLE_VALUE;
// Implies `fileNameW[len] = L'\0';` and `len` includes the null terminator
for (int i = 0; i < len - 1; ++i)
{
if (fileNameW[i] == L'/')
fileNameW[i] = L'\\';
}
return openatW(dfd, fileNameW, (uint16_t)(len - 1), directory);
}
bool ffAppendFileBufferRelative(HANDLE dfd, const char* fileName, FFstrbuf* buffer)
{
HANDLE FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, false);
@@ -371,3 +388,8 @@ FFNativeFD ffGetNullFD(void)
});
return hNullFile;
}
bool ffRemoveFile(const char* fileName)
{
return DeleteFileA(fileName) != FALSE;
}
@@ -2,11 +2,11 @@
#include "common/color.h"
#include "common/jsonconfig.h"
#include "common/printing.h"
#include "common/io/io.h"
#include "common/io.h"
#include "common/time.h"
#include "common/stringUtils.h"
#include "detection/version/version.h"
#include "modules/modules.h"
#include "util/stringUtils.h"
#include <assert.h>
#include <ctype.h>
@@ -158,6 +158,16 @@ 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))
{
@@ -220,9 +230,10 @@ static bool matchesJsonArray(const char* str, yyjson_val* val)
return false;
}
static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
static const char* printJsonConfig(FFdata* data, bool prepare)
{
yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc);
yyjson_mut_doc* jsonDoc = data->resultDoc;
yyjson_val* const root = yyjson_doc_get_root(data->configDoc);
assert(root);
if (!yyjson_is_obj(root))
@@ -288,6 +299,9 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
else
return "modules must be an array of strings or objects";
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, type, ':'))
continue;
if(prepare)
prepareModuleJsonObject(type, module);
else
@@ -319,9 +333,10 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
return NULL;
}
void ffPrintJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
void ffPrintJsonConfig(FFdata* data, bool prepare)
{
const char* error = printJsonConfig(prepare, jsonDoc);
yyjson_mut_doc* jsonDoc = data->resultDoc;
const char* error = printJsonConfig(data, prepare);
if (error)
{
if (jsonDoc)
+4 -4
View File
@@ -1,7 +1,7 @@
#include "kmod.h"
#include "common/kmod.h"
#if __linux__
#include "common/io/io.h"
#include "common/io.h"
bool ffKmodLoaded(const char* modName)
{
@@ -32,7 +32,7 @@ bool ffKmodLoaded(const char* modName)
return modfind(modName) >= 0;
}
#elif __NetBSD__
#include "util/stringUtils.h"
#include "common/stringUtils.h"
#include <sys/module.h>
#include <sys/param.h>
@@ -75,7 +75,7 @@ bool ffKmodLoaded(const char* modName)
return false;
}
#elif __APPLE__
#include "util/apple/cf_helpers.h"
#include "common/apple/cf_helpers.h"
#include <IOKit/kext/KextManager.h>
#include <CoreFoundation/CoreFoundation.h>
+19
View File
@@ -0,0 +1,19 @@
#include "common/memrchr.h"
#include <stddef.h>
#include <stdint.h>
void* memrchr(const void* s, int c, size_t n)
{
if (n == 0) return NULL;
const uint8_t uc = (uint8_t) c;
const uint8_t* p = (const uint8_t*) s + n;
while (n--)
{
if (*--p == uc) return (void*) p;
}
return NULL;
}
@@ -1,4 +1,4 @@
#include "netif.h"
#include "common/netif.h"
#ifndef _WIN32
#include <net/if.h>
@@ -1,7 +1,6 @@
#include "netif.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include "common/netif.h"
#include "common/io.h"
#include "common/mallocHelper.h"
#include <net/if.h>
#include <net/if_dl.h>
@@ -73,7 +72,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
}
int pid = getpid();
uint32_t pid = instance.state.platform.pid;
struct {
struct rt_msghdr hdr;
@@ -86,7 +85,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
.rtm_version = RTM_VERSION,
.rtm_addrs = RTA_DST | RTA_IFP | RTA_IFA,
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
.rtm_pid = pid,
.rtm_pid = (pid_t) pid,
.rtm_seq = 1,
},
.dst = {
@@ -100,7 +99,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
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))
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == (pid_t) pid))
;
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
@@ -146,7 +145,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
}
int pid = getpid();
uint32_t pid = instance.state.platform.pid;
struct {
struct rt_msghdr hdr;
@@ -159,7 +158,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
.rtm_version = RTM_VERSION,
.rtm_addrs = RTA_DST | RTA_IFP,
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
.rtm_pid = pid,
.rtm_pid = (pid_t) pid,
.rtm_seq = 2,
},
.dst = {
@@ -173,7 +172,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
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))
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == (pid_t) pid))
;
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
@@ -1,7 +1,6 @@
#include "netif.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include "common/netif.h"
#include "common/io.h"
#include "common/mallocHelper.h"
#include <net/if.h>
#include <net/if_dl.h>
@@ -1,5 +1,5 @@
#include "netif.h"
#include "common/io/io.h"
#include "common/netif.h"
#include "common/io.h"
#include <net/if.h>
#include <stdio.h>
@@ -1,6 +1,6 @@
#include "netif.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include "common/netif.h"
#include "common/io.h"
#include "common/mallocHelper.h"
#include <arpa/inet.h>
#include <net/if.h>
@@ -1,7 +1,7 @@
#include "netif.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include "util/debug.h"
#include "common/netif.h"
#include "common/io.h"
#include "common/mallocHelper.h"
#include "common/debug.h"
#include <arpa/inet.h>
#include <linux/rtnetlink.h>
@@ -19,7 +19,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
}
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
unsigned pid = (unsigned) getpid();
uint32_t pid = instance.state.platform.pid;
FF_DEBUG("Process PID: %u", pid);
// Bind socket
@@ -89,7 +89,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
uint32_t minMetric = UINT32_MAX;
int routeCount = 0;
FF_MAYBE_UNUSED int routeCount = 0;
while (true)
{
@@ -151,6 +151,12 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
continue;
}
// Skip local/loopback routes
if (rtm->rtm_scope == RT_SCOPE_HOST || rtm->rtm_type == RTN_LOCAL) {
FF_DEBUG("Skipping local route #%d (scope=%d, type=%d)", routeCount, rtm->rtm_scope, rtm->rtm_type);
continue;
}
FF_DEBUG("Processing IPv4 default route candidate #%d", routeCount);
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
@@ -229,7 +235,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
}
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
unsigned pid = (unsigned) getpid();
uint32_t pid = instance.state.platform.pid;
FF_DEBUG("Process PID: %u", pid);
// Bind socket
@@ -299,7 +305,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
uint32_t minMetric = UINT32_MAX;
int routeCount = 0;
FF_MAYBE_UNUSED int routeCount = 0;
while (true)
{
@@ -360,6 +366,12 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
continue;
}
// Skip local/loopback routes
if (rtm->rtm_scope == RT_SCOPE_HOST || rtm->rtm_type == RTN_LOCAL) {
FF_DEBUG("Skipping local route #%d (scope=%d, type=%d)", routeCount, rtm->rtm_scope, rtm->rtm_type);
continue;
}
FF_DEBUG("Processing IPv6 default route candidate #%d", routeCount);
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
@@ -1,5 +1,5 @@
#include "netif.h"
#include "util/mallocHelper.h"
#include "common/netif.h"
#include "common/mallocHelper.h"
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
#include <iphlpapi.h>
@@ -1,8 +1,8 @@
#include "fastfetch.h"
#include "common/library.h"
#include "common/networking/networking.h"
#include "util/stringUtils.h"
#include "util/debug.h"
#include "common/networking.h"
#include "common/stringUtils.h"
#include "common/debug.h"
#ifdef FF_HAVE_ZLIB
#include <zlib.h>
@@ -12,7 +12,6 @@ struct FFZlibLibrary
FF_LIBRARY_SYMBOL(inflateInit2_)
FF_LIBRARY_SYMBOL(inflate)
FF_LIBRARY_SYMBOL(inflateEnd)
FF_LIBRARY_SYMBOL(inflateGetHeader)
bool inited;
} zlibData;
@@ -22,7 +21,7 @@ const char* ffNetworkingLoadZlibLibrary(void)
if (!zlibData.inited)
{
zlibData.inited = true;
FF_LIBRARY_LOAD(zlib, "dlopen libz failed",
FF_LIBRARY_LOAD_MESSAGE(zlib,
#ifdef _WIN32
"zlib1"
#else
@@ -32,7 +31,6 @@ const char* ffNetworkingLoadZlibLibrary(void)
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;
@@ -69,6 +67,8 @@ static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize)
// Decompress gzip content
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
{
assert(headerEnd != NULL && *headerEnd == '\r');
// Calculate header size
uint32_t headerSize = (uint32_t) (headerEnd - buffer->chars);
@@ -86,15 +86,15 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
const char* bodyStart = headerEnd + 4; // Skip delimiter
// Calculate compressed content size
uint32_t compressedSize = buffer->length - headerSize - 4;
if (compressedSize <= 0) {
if (buffer->length <= headerSize + 4) {
// No content to decompress
FF_DEBUG("Compressed content size is 0, skipping decompression");
return true;
}
// Calculate compressed content size
uint32_t compressedSize = buffer->length - headerSize - 4;
// 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");
@@ -137,7 +137,7 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
// 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
decompressedBuffer.chars[decompressedBuffer.length] = '\0';
ffStrbufEnsureFree(&decompressedBuffer, decompressedBuffer.length / 2);
@@ -155,7 +155,7 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
// Calculate decompressed size
uint32_t decompressedSize = (uint32_t)(availableOut - zs.avail_out);
decompressedBuffer.length += decompressedSize;
decompressedBuffer.chars[decompressedSize] = '\0'; // Ensure null-terminated string
decompressedBuffer.chars[decompressedBuffer.length] = '\0';
FF_DEBUG("Successfully decompressed %u bytes compressed data to %u bytes", compressedSize, decompressedBuffer.length);
// Modify Content-Length header and remove Content-Encoding header
@@ -171,7 +171,7 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
}
else if (ffStrStartsWithIgnCase(line, "Content-Length:"))
{
ffStrbufAppendF(&newBuffer, "Content-Length: %u\r\n", decompressedSize);
ffStrbufAppendF(&newBuffer, "Content-Length: %u\r\n", decompressedBuffer.length);
continue;
}
else if (line[0] == '\r')
@@ -181,7 +181,7 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd)
break;
}
ffStrbufAppendS(&newBuffer, line);
ffStrbufAppendS(&newBuffer, line); // Including the trailing \r
ffStrbufAppendC(&newBuffer, '\n');
}
@@ -1,10 +1,10 @@
#include "fastfetch.h"
#include "common/networking/networking.h"
#include "common/networking.h"
#include "common/time.h"
#include "common/library.h"
#include "util/stringUtils.h"
#include "util/mallocHelper.h"
#include "util/debug.h"
#include "common/stringUtils.h"
#include "common/mallocHelper.h"
#include "common/debug.h"
#include <unistd.h>
#include <poll.h>
@@ -34,11 +34,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state)
#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
int flag = 1;
if (setsockopt(state->sockfd, IPPROTO_TCP,
#ifdef __APPLE__
// https://github.com/rust-lang/libc/pull/3135
@@ -186,15 +182,12 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
FF_DEBUG("Initializing network connection state: host=%s, path=%s", host, path);
// Initialize command and host information
ffStrbufInitA(&state->command, 64);
ffStrbufInitA(&state->command, 128);
ffStrbufAppendS(&state->command, "GET ");
ffStrbufAppendS(&state->command, path);
ffStrbufAppendS(&state->command, " HTTP/1.0\nHost: ");
ffStrbufAppendS(&state->command, " HTTP/1.0\r\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
ffStrbufAppendS(&state->command, "\r\nConnection: close\r\n"); // Explicitly tell the server we don't need to keep the connection
// If compression needs to be enabled
if (state->compression) {
@@ -221,9 +214,10 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
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)
int gaiRes = getaddrinfo(host, "80", &hints, &state->addr);
if(gaiRes != 0)
{
FF_DEBUG("getaddrinfo() failed: %s", gai_strerror(errno));
FF_DEBUG("getaddrinfo() failed: %s (res=%d)", gai_strerror(gaiRes), gaiRes);
ret = "getaddrinfo() failed";
goto error;
}
@@ -360,6 +354,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
{
assert(buffer->allocated > 0);
FF_DEBUG("Preparing to receive HTTP response");
uint32_t timeout = state->timeout;
@@ -390,15 +385,25 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
// 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";
int pollRes = poll(&(struct pollfd) {
.fd = state->sockfd,
.events = POLLIN
}, 1, timeout > 0 ? (int) timeout : -1);
if (pollRes == 0)
{
FF_DEBUG("poll() timed out after %u ms", timeout);
close(state->sockfd);
state->sockfd = -1;
return "poll() timeout";
}
else if (pollRes == -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
@@ -415,12 +420,14 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
FF_DEBUG("Starting data reception");
FF_MAYBE_UNUSED int recvCount = 0;
uint32_t contentLength = 0;
char* headerEnd = NULL;
uint32_t headerEnd = 0;
do {
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
++recvCount, buffer->length, ffStrbufGetFree(buffer));
// We set `Connection: close`, so the server will close the connection when done.
// Thus we can use MSG_WAITALL to wait until the buffer is full or the connection is closed.
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, ffStrbufGetFree(buffer), MSG_WAITALL);
if (received <= 0) {
@@ -438,10 +445,11 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
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));
if (headerEnd == 0) {
char* pHeaderEnd = memmem(buffer->chars, buffer->length, "\r\n\r\n", 4);
if (pHeaderEnd) {
headerEnd = (uint32_t)(pHeaderEnd - buffer->chars);
FF_DEBUG("Found HTTP header end marker, position: %u", headerEnd);
// Check for Content-Length header to pre-allocate enough memory
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
@@ -451,7 +459,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
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);
FF_DEBUG("Extended receive buffer to %u bytes", buffer->allocated);
}
}
}
@@ -467,12 +475,12 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
return "Empty server response received";
}
if (headerEnd == NULL) {
if (headerEnd == 0) {
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);
if (contentLength > 0 && buffer->length != contentLength + headerEnd + 4) {
FF_DEBUG("Received content length mismatches: %u != %u", buffer->length, contentLength + headerEnd + 4);
return "Content length mismatch";
}
@@ -487,7 +495,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
#ifdef FF_HAVE_ZLIB
if (state->compression) {
FF_DEBUG("Content received, checking if compressed");
if (!ffNetworkingDecompressGzip(buffer, headerEnd)) {
if (!ffNetworkingDecompressGzip(buffer, buffer->chars + headerEnd)) {
FF_DEBUG("Decompression failed or invalid compression format");
return "Failed to decompress or invalid format";
} else {
@@ -3,9 +3,9 @@
//Must be included after <mswsock.h>
#include "fastfetch.h"
#include "common/networking/networking.h"
#include "util/stringUtils.h"
#include "util/debug.h"
#include "common/networking.h"
#include "common/stringUtils.h"
#include "common/debug.h"
static LPFN_CONNECTEX ConnectEx;
@@ -19,6 +19,7 @@ static const char* initWsaData(WSADATA* wsaData)
if(LOBYTE(wsaData->wVersion) != 2 || HIBYTE(wsaData->wVersion) != 2) {
FF_DEBUG("Invalid wsaData version found: %d.%d", LOBYTE(wsaData->wVersion), HIBYTE(wsaData->wVersion));
WSACleanup();
return "Invalid wsaData version found";
}
@@ -26,6 +27,7 @@ static const char* initWsaData(WSADATA* wsaData)
SOCKET sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == INVALID_SOCKET) {
FF_DEBUG("socket(AF_INET, SOCK_STREAM) failed");
WSACleanup();
return "socket(AF_INET, SOCK_STREAM) failed";
}
@@ -36,6 +38,8 @@ static const char* initWsaData(WSADATA* wsaData)
&ConnectEx, sizeof(ConnectEx),
&dwBytes, NULL, NULL) != 0) {
FF_DEBUG("WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
closesocket(sockfd);
WSACleanup();
return "WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed";
}
@@ -144,26 +148,35 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
return "bind() failed";
}
// Initialize overlapped structure for asynchronous I/O
memset(&state->overlapped, 0, sizeof(OVERLAPPED));
// Initialize overlapped structure with WSA event for asynchronous I/O
state->overlapped = (OVERLAPPED){
.hEvent = WSACreateEvent()
};
if (state->overlapped.hEvent == WSA_INVALID_EVENT) {
FF_DEBUG("WSACreateEvent() failed");
closesocket(state->sockfd);
freeaddrinfo(addr);
state->sockfd = INVALID_SOCKET;
return "WSACreateEvent() failed";
}
// 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
ffStrbufInitA(&state->command, 128);
ffStrbufAppendS(&state->command, "GET ");
ffStrbufAppendS(&state->command, path);
ffStrbufAppendS(&state->command, " HTTP/1.0\r\nHost: ");
ffStrbufAppendS(&state->command, host);
ffStrbufAppendS(&state->command, "\r\nConnection: 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(&state->command, "Accept-Encoding: gzip\r\n");
}
ffStrbufAppendS(&command, headers);
ffStrbufAppendS(&command, "\r\n");
ffStrbufAppendS(&state->command, headers);
ffStrbufAppendS(&state->command, "\r\n");
#ifdef TCP_FASTOPEN
if (state->tfo)
@@ -182,10 +195,10 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
}
#endif
FF_DEBUG("Using ConnectEx to send %u bytes of data", command.length);
FF_DEBUG("Using ConnectEx to send %u bytes of data", state->command.length);
DWORD sent = 0;
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int)addr->ai_addrlen,
command.chars, command.length, &sent, &state->overlapped);
state->command.chars, state->command.length, &sent, &state->overlapped);
freeaddrinfo(addr);
addr = NULL;
@@ -195,8 +208,10 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
if (WSAGetLastError() != WSA_IO_PENDING)
{
FF_DEBUG("ConnectEx() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
WSACloseEvent(state->overlapped.hEvent);
closesocket(state->sockfd);
state->sockfd = INVALID_SOCKET;
ffStrbufDestroy(&state->command);
return "ConnectEx() failed";
}
else
@@ -215,6 +230,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
{
assert(buffer->allocated > 0);
FF_DEBUG("Preparing to receive HTTP response");
if (state->sockfd == INVALID_SOCKET)
@@ -226,13 +242,20 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
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("WSAWaitForMultipleEvents with timeout: %u ms", timeout);
DWORD result = WSAWaitForMultipleEvents(1, &state->overlapped.hEvent, TRUE, timeout, FALSE);
if (result != WSA_WAIT_EVENT_0)
{
FF_DEBUG("WaitForSingleObject failed or timed out");
if (result == WSA_WAIT_TIMEOUT) {
FF_DEBUG("WSAWaitForMultipleEvents timed out");
} else {
FF_DEBUG("WSAWaitForMultipleEvents failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
}
CancelIo((HANDLE) state->sockfd);
WSACloseEvent(state->overlapped.hEvent);
closesocket(state->sockfd);
return "WaitForSingleObject(state->sockfd) failed or timeout";
ffStrbufDestroy(&state->command);
return "WSAWaitForMultipleEvents() failed or timeout";
}
}
@@ -241,8 +264,20 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
{
FF_DEBUG("WSAGetOverlappedResult failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
closesocket(state->sockfd);
WSACloseEvent(state->overlapped.hEvent);
ffStrbufDestroy(&state->command);
return "WSAGetOverlappedResult() failed";
}
FF_DEBUG("WSAGetOverlappedResult succeeded, %u bytes sent", (unsigned) transfer);
ffStrbufDestroy(&state->command);
WSACloseEvent(state->overlapped.hEvent);
state->overlapped.hEvent = NULL;
if (setsockopt(state->sockfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0)
{
FF_DEBUG("Failed to update connect context: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
// Not a critical error, continue anyway
}
if(timeout > 0)
{
@@ -252,12 +287,16 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
// Set larger receive buffer for better performance
int rcvbuf = 65536; // 64KB
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&rcvbuf, sizeof(rcvbuf));
if (setsockopt(state->sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&rcvbuf, sizeof(rcvbuf)))
{
FF_DEBUG("Failed to set SO_RCVBUF: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
// Not a critical error, continue anyway
}
FF_DEBUG("Starting data reception");
FF_MAYBE_UNUSED int recvCount = 0;
uint32_t contentLength = 0;
char* headerEnd = NULL;
uint32_t headerEnd = 0;
do {
FF_DEBUG("Data reception loop #%d, current buffer size: %u, available space: %u",
@@ -280,10 +319,11 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
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));
if (headerEnd == 0) {
char* pHeaderEnd = strstr(buffer->chars, "\r\n\r\n");
if (pHeaderEnd) {
headerEnd = (uint32_t)(pHeaderEnd - buffer->chars);
FF_DEBUG("Found HTTP header end marker, position: %u", headerEnd);
// Check for Content-Length header to pre-allocate enough memory
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
@@ -309,10 +349,14 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
return "Empty server response received";
}
if (headerEnd == NULL) {
if (headerEnd == 0) {
FF_DEBUG("No HTTP header end marker found");
return "No HTTP header end found";
}
if (contentLength > 0 && buffer->length != contentLength + headerEnd + 4) {
FF_DEBUG("Received content length mismatches: %u != %u", buffer->length, contentLength + headerEnd + 4);
return "Content length mismatch";
}
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",
@@ -326,7 +370,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
#ifdef FF_HAVE_ZLIB
if (state->compression) {
FF_DEBUG("Content received, checking if compressed");
if (!ffNetworkingDecompressGzip(buffer, headerEnd)) {
if (!ffNetworkingDecompressGzip(buffer, buffer->chars + headerEnd)) {
FF_DEBUG("Decompression failed or invalid compression format");
return "Failed to decompress or invalid format";
} else {
@@ -1,7 +1,7 @@
#include "fastfetch.h"
#include "common/option.h"
#include "common/color.h"
#include "util/stringUtils.h"
#include "common/stringUtils.h"
// Return start position of the inner key if the argument key belongs to the module specified, NULL otherwise
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName)
@@ -166,6 +166,22 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
exit(479);
}
}
else if (value[0] == '@')
{
// Xterm 256 color
++value;
char* pend = NULL;
uint32_t color = (uint32_t) strtoul(value, &pend, 10);
if (pend == value || color > 255) {
fprintf(stderr, "Error: invalid 256 color code found: %s\n", value);
exit(479);
}
ffStrbufAppendS(buffer, FF_COLOR_FG_256);
ffStrbufAppendUInt(buffer, color);
value = pend;
continue;
}
else if (value[0] == '#')
{
// RGB color
+3 -14
View File
@@ -1,7 +1,6 @@
#include "path.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include "common/path.h"
#include "common/io.h"
#include "common/stringUtils.h"
#if !_WIN32
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
@@ -64,13 +63,3 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
return NULL;
}
#endif
bool ffIsAbsolutePath(const char* path)
{
#ifdef _WIN32
return (ffCharIsEnglishAlphabet(path[0]) && path[1] == ':' && (path[2] == '\\' || path[2] == '/')) // drive letter path
|| (path[0] == '\\' && path[1] == '\\'); // UNC path
#else
return path[0] == '/';
#endif
}
@@ -3,8 +3,8 @@
#include "common/color.h"
#include "common/option.h"
#include "common/jsonconfig.h"
#include "util/textModifier.h"
#include "util/stringUtils.h"
#include "common/textModifier.h"
#include "common/stringUtils.h"
static void appendOutputColor(FFstrbuf* buffer, const FFModuleArgs* module)
{
@@ -1,7 +1,7 @@
#include "fastfetch.h"
#include "common/printing.h"
#include "common/textModifier.h"
#include "logo/logo.h"
#include "util/textModifier.h"
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType)
{
@@ -28,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)
@@ -136,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))
@@ -1,8 +1,8 @@
#include "fastfetch.h"
#include "common/processing.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include "util/mallocHelper.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/mallocHelper.h"
#include <stdlib.h>
#include <unistd.h>
@@ -58,11 +58,9 @@ static inline int ffPipe2(int* fds, int flags)
// Not thread-safe
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
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";
@@ -146,7 +144,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if(childPid == 0)
{
//Child
// Child process
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
putenv("LANG=C.UTF-8");
@@ -157,11 +155,24 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
#endif
close(pipes[1]);
outHandle->pid = childPid;
outHandle->pipeRead = pipes[0];
return NULL;
}
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
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)
{
@@ -173,30 +184,13 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
}
else if (pollret < 0)
{
if (errno == EINTR)
{
// 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";
}
}
else if (pollfd.revents & POLLERR)
else if (pollret < 0 || (pollfd.revents & POLLERR))
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) error";
return pollret < 0
? "poll(&pollfd, 1, timeout) error: pollret < 0"
: "poll(&pollfd, 1, timeout) error: pollfd.revents & POLLERR";
}
}
@@ -211,20 +205,15 @@ 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;
}
return NULL;
}
else if (nRead < 0)
{
if (errno == EAGAIN)
return NULL;
else
break;
}
};
break;
}
return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed";
}
@@ -233,6 +222,7 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
{
assert(processName->length > 0);
ffStrbufClear(exe);
if (exePath) ffStrbufClear(exePath);
#if defined(__linux__) || defined(__GNU__)
@@ -281,9 +271,14 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
if (length > 0) // doesn't contain trailing NUL
{
buf[length] = '\0';
ffStrbufEnsureFixedLengthFree(exePath, (uint32_t)length);
ffStrbufAppendNS(exePath, (uint32_t)length, buf);
// When the process is a deleted executable, the resolved path is like `/usr/bin/app (deleted)`
// But we can still access the binary via `/proc/pid/exe`. See #2136
if (ffPathExists(buf, FF_PATHTYPE_ANY))
ffStrbufSetNS(exePath, (uint32_t)length, buf);
}
if (exePath->length == 0)
ffStrbufSetS(exePath, filePath);
}
#elif defined(__APPLE__)
@@ -325,16 +320,21 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
ffStrbufSetS(exe, arg0);
}
}
else
if (exePath || exe->length == 0)
{
char buf[PROC_PIDPATHINFO_MAXSIZE];
int length = proc_pidpath(pid, buf, ARRAY_SIZE(buf));
if (length > 0)
{
ffStrbufEnsureFixedLengthFree(exe, (uint32_t) length);
ffStrbufAppendNS(exe, (uint32_t) length, buf);
if (exe->length == 0)
ffStrbufSetNS(exe, (uint32_t) length, buf);
if (exePath)
ffStrbufSet(exePath, exe);
{
// We don't use exec_path above as exePath because it's a relative path and can be different
// from the actual executable being run (for example, when the original file is moved)
ffStrbufSetNS(exePath, (uint32_t) length, buf);
}
}
}
@@ -410,8 +410,7 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
if (length > 0) // doesn't contain trailing NUL
{
buf[length] = '\0';
ffStrbufEnsureFixedLengthFree(exePath, (uint32_t)length);
ffStrbufAppendNS(exePath, (uint32_t)length, buf);
ffStrbufSetNS(exePath, (uint32_t)length, buf);
}
}
@@ -1,8 +1,11 @@
#include "fastfetch.h"
#include "common/processing.h"
#include "common/io/io.h"
#include "common/io.h"
#include "common/windows/unicode.h"
#include "common/windows/nt.h"
#include <Windows.h>
#include <stdalign.h>
#include <windows.h>
#include <ntstatus.h>
#include <winternl.h>
@@ -45,12 +48,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", instance.state.platform.pid, ++pidCounter);
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = CreateNamedPipeW(
pipeName,
@@ -82,52 +86,67 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
PROCESS_INFORMATION piProcInfo = {};
BOOL success;
STARTUPINFOA siStartInfo = {
.cb = sizeof(siStartInfo),
.dwFlags = STARTF_USESTDHANDLES,
};
if (useStdErr)
{
STARTUPINFOA siStartInfo = {
.cb = sizeof(siStartInfo),
.dwFlags = STARTF_USESTDHANDLES,
};
if (useStdErr)
{
siStartInfo.hStdOutput = ffGetNullFD();
siStartInfo.hStdError = hChildPipeWrite;
}
else
{
siStartInfo.hStdOutput = hChildPipeWrite;
siStartInfo.hStdError = ffGetNullFD();
}
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
{
@@ -136,7 +155,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
switch (GetLastError())
{
case ERROR_IO_PENDING:
#if __aarch64__
#if !FF_WIN7_COMPAT
if (!GetOverlappedResultEx(hChildPipeRead, &overlapped, &nRead, timeout < 0 ? INFINITE : (DWORD) timeout, FALSE))
#else
// To support Windows 7
@@ -156,7 +175,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
return "GetOverlappedResult"
#if __aarch64__
#if !FF_WIN7_COMPAT
"Ex"
#endif
"(hChildPipeRead) failed";
@@ -164,7 +183,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
break;
case ERROR_BROKEN_PIPE:
return NULL;
goto exit;
default:
CancelIo(hChildPipeRead);
@@ -175,13 +194,27 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
ffStrbufAppendNS(buffer, nRead, str);
} while (nRead > 0);
exit:
{
PROCESS_BASIC_INFORMATION info = {};
ULONG size;
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size)))
{
assert(size == sizeof(info));
if (info.ExitStatus != STILL_ACTIVE && info.ExitStatus != 0)
return "Child process exited with an error";
}
else
return "NtQueryInformationProcess(ProcessBasicInformation) failed";
}
return NULL;
}
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui)
{
FF_AUTO_CLOSE_FD HANDLE hProcess = pid == 0
? GetCurrentProcess()
? NtCurrentProcess()
: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid);
if (hProcess == NULL)
@@ -204,12 +237,15 @@ bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFst
}
if(exe)
{
DWORD bufSize = exe->allocated;
if(QueryFullProcessImageNameA(hProcess, 0, exe->chars, &bufSize))
// TODO: It's possible to query the command line with `NtQueryInformationProcess(60/*ProcessCommandLineInformation*/)` since Windows 8.1
alignas(alignof(UNICODE_STRING)) uint8_t buffer[4096];
ULONG size;
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, &buffer, sizeof(buffer), &size)))
{
// We use full path here
// Querying command line of remote processes in Windows requires either WMI or ReadProcessMemory
exe->length = bufSize;
UNICODE_STRING* imageName = (UNICODE_STRING*)buffer;
ffStrbufSetNWS(exe, imageName->Length / sizeof(wchar_t), imageName->Buffer);
if (exePath) ffStrbufSet(exePath, exe);
}
else
@@ -1,12 +1,12 @@
#include "fastfetch.h"
#include "common/properties.h"
#include "common/io/io.h"
#include "util/mallocHelper.h"
#include "common/io.h"
#include "common/mallocHelper.h"
#include <stdlib.h>
#include <ctype.h>
#ifdef _WIN32
#include "util/windows/getline.h"
#include "common/windows/getline.h"
#endif
bool ffParsePropLinePointer(const char** line, const char* start, FFstrbuf* buffer)
@@ -2,7 +2,7 @@
#include "common/settings.h"
#include "common/library.h"
#include "common/thread.h"
#include "common/io/io.h"
#include "common/io.h"
#include <string.h>
+1 -1
View File
@@ -1,4 +1,4 @@
#include "size.h"
#include "common/size.h"
#include <inttypes.h>
@@ -1,8 +1,8 @@
#include "smbiosHelper.h"
#include "common/io/io.h"
#include "util/unused.h"
#include "util/mallocHelper.h"
#include "util/debug.h"
#include "common/smbiosHelper.h"
#include "common/io.h"
#include "common/unused.h"
#include "common/mallocHelper.h"
#include "common/debug.h"
bool ffIsSmbiosValueSet(FFstrbuf* value)
{
@@ -402,7 +402,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
#endif
FF_DEBUG("Parsing SMBIOS table structures");
int structureCount = 0;
FF_MAYBE_UNUSED int structureCount = 0;
for (
const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer.chars;
(const uint8_t*) header < (const uint8_t*) buffer.chars + buffer.length;
@@ -1,4 +1,4 @@
#include "sysctl.h"
#include "common/sysctl.h"
#include <stdlib.h>
@@ -1,7 +1,7 @@
#include "fastfetch.h"
#include "common/temps.h"
#include "util/textModifier.h"
#include "util/stringUtils.h"
#include "common/textModifier.h"
#include "common/stringUtils.h"
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module)
{
+95
View File
@@ -0,0 +1,95 @@
#include "common/time.h"
#include <stdio.h>
char ffTimeInternalBuffer[64]; // Reduce memory usage and prevent redundant allocations
#ifdef _WIN32
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
#endif
const char* ffTimeToFullStr(uint64_t msec)
{
if (msec == 0) return "";
time_t tsec = (time_t) (msec / 1000);
const struct tm* tm = localtime(&tsec);
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;
}
const char* ffTimeToShortStr(uint64_t msec)
{
if (msec == 0) return "";
time_t tsec = (time_t) (msec / 1000);
strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer), "%F %T", localtime(&tsec));
return ffTimeInternalBuffer;
}
const char* ffTimeToTimeStr(uint64_t msec)
{
if (msec == 0) return "";
time_t tsec = (time_t) (msec / 1000);
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
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;
}
#ifdef _WIN32
double ffQpcMultiplier;
__attribute__((constructor))
static void ffTimeInitQpcMultiplier(void)
{
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
ffQpcMultiplier = 1000. / (double) frequency.QuadPart;
}
#endif
@@ -1,4 +1,4 @@
#include "wcwidth.h"
#include "common/wcwidth.h"
#include "3rdparty/widecharwidth/widechar_width_c.h"
int mk_wcwidth(uint32_t wc)

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