Compare commits

...

286 Commits

Author SHA1 Message Date
Carter Li 06ecc9c480 Merge pull request #2217 from fastfetch-cli/dev
Release: v2.60.0
2026-03-06 21:08:19 -06:00
李通洲 50288d91e4 Doc: updates changelog [ci skip] 2026-03-07 10:43:16 +08:00
李通洲 499b4ff445 Kmod (Windows): don't specify maybe_unused on used params 2026-03-07 10:43:01 +08:00
李通洲 dd0021cd5e GPU (Windows): adds kernel version check before D3DKMT syscall 2026-03-07 10:34:21 +08:00
李通洲 f5b70dd8b7 Doc: updates changelog 2026-03-07 09:31:26 +08:00
李通洲 8f8ca11203 Kernel (Windows): simplifies kernel version detection 2026-03-07 09:26:13 +08:00
李通洲 121d399641 CPUUsage (Windows): simplifies Win10 detection 2026-03-07 09:24:38 +08:00
李通洲 26ae4eb21b Chore (Windows): removes unnecessary headers 2026-03-07 01:18:07 +08:00
李通洲 52a81dbdc4 Disk (Windows): reads SystemWindowsDirectory directly from SharedUserData 2026-03-07 00:35:07 +08:00
李通洲 f924a8bf06 Uptime: reads (System|Interrupt)Time directly from SharedUserData 2026-03-07 00:09:08 +08:00
李通洲 c7363f904a Common (Windows): adds definition of KUSER_SHARED_DATA 2026-03-06 23:59:19 +08:00
李通洲 53ffe8459f Global: applies Copilot's suggestions 2026-03-06 18:33:29 +08:00
李通洲 1b702e123e Release: v2.60.0 2026-03-06 15:27:55 +08:00
李通洲 14dccce393 CI (Linux): builds fastfetch with chafa support 2026-03-06 15:27:55 +08:00
李通洲 d040cc810f SMBIOS (Windows): fixes issues raised by Copilot 2026-03-06 14:46:51 +08:00
李通洲 224bea2559 WM (Windows): fixes issues raised by Copilot 2026-03-06 14:36:40 +08:00
李通洲 777d3e599d WM (macOS): fixes issues raised by Copilot 2026-03-06 14:09:13 +08:00
李通洲 7c47bc2656 WM: honors general.detectVersion 2026-03-06 11:10:35 +08:00
李通洲 e4d31381d8 WM (macOS): fetches WM plugin version 2026-03-06 11:08:41 +08:00
Dariqq abf8d75454 Chore (Windows): adds missing header (#2215) 2026-03-05 18:39:03 -06:00
李通洲 2ce152beaf SmbiosHelper (Windows): prefers NtQuerySystemInformation 2026-03-05 10:18:18 +08:00
李通洲 766ed07999 Refactor: prefers ffStr* 2026-03-05 10:16:24 +08:00
李通洲 ddc2131343 Chore (Windows): adds comments 2026-03-05 10:16:11 +08:00
Carter Li b64d8a013d DisplayServer (Linux): check if RANDR is running in Emulation mode 2026-03-05 10:12:38 +08:00
Carter Li e6db59fdde WM (Linux): fix niri version detection logic 2026-03-05 08:45:56 +08:00
李通洲 7ea0bbfb21 CPU / CPUCache (Windows): prefers NtQuerySystemInformation(Ex) 2026-03-03 16:01:36 +08:00
李通洲 ab041e0ad2 JsonSchema: update [ci skip] 2026-03-03 14:34:45 +08:00
李通洲 207f742624 TerminalFont (Windows): hardens the Windows Terminal font detection logic 2026-03-03 14:21:19 +08:00
李通洲 68f0b11b6f WM (Windows): loads wintrust lazily 2026-03-03 11:00:41 +08:00
李通洲 b86c0880b9 Bluetooth (Windows): adds a string variant helper; removes propsys dependency 2026-03-03 11:00:37 +08:00
李通洲 75f4a3d92d Platform (Windows): don't error out on i686 2026-03-03 08:47:34 +08:00
李通洲 70fa1341a8 Bootmgr (Windows): prefers NT API 2026-03-03 08:47:21 +08:00
李通洲 0a55314d37 WM (Windows): uses WinVerifyTrustEx consistantly 2026-03-03 00:27:28 +08:00
李通洲 2198e6123e DisplayServer (Windows): uses the standard GetDpiForMonitor to query scale factors 2026-03-03 00:23:36 +08:00
李通洲 dd37ee0e50 Doc: updates README [ci skip] 2026-03-01 19:27:33 +08:00
李通洲 7006ae0420 CMake (Windows): disable ENABLE_WIN7_COMPAT by default 2026-03-01 19:12:35 +08:00
李通洲 86458ab32a Kmod (SunOS): adds support 2026-03-01 14:44:29 +08:00
李通洲 67ca907e38 Kmod (Windows): adds support 2026-03-01 14:06:54 +08:00
李通洲 e15d06bbad Chore (Windows): move NT stuff to common 2026-03-01 13:58:38 +08:00
zamhedonia eb53797174 Logo (Builtin): adds support for Emmabuntüs (#2207)
* Logo (Builtin): adds Emmabuntüs Logo

* Add Detection for Emmabuntüs

* Update ASCII art in emmabuntus.txt

* Remove duplicate name for Emmabuntus logo

* Update emmabuntus.txt

* Update colors for Emmabuntus logo

---------

Co-authored-by: zamhedonia <zamhedonia@gmx.de>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-03-01 00:13:16 +08:00
李通洲 c8c32a78b0 Presets: adds examples/32 2026-02-28 18:51:36 +08:00
李通洲 1c032624ac Title: adds {cwd-tilde} support 2026-02-28 18:44:13 +08:00
Carter Li 5087ea77b4 Presets: replaces outer single-line border with double-lines in examples/25 2026-02-28 17:48:36 +08:00
李通洲 b6b42e69c3 DisplayServer (Windows): reduce system dependencies 2026-02-28 10:37:03 +08:00
李通洲 000a688bb6 TerminalShell (Windows): improves logic of GUI program check 2026-02-28 10:06:13 +08:00
李通洲 3e25b213b1 WM (Windows): supports komorebi detection 2026-02-28 10:03:27 +08:00
李通洲 a69cf456ea Binary (Windows): removes imagehlp dep 2026-02-27 22:59:46 +08:00
李通洲 072b76cb12 WM: defaults detectPlugin to true 2026-02-27 18:26:53 +08:00
Carter Li ca8f54d331 CI: forwards envs & upgrades deps 2026-02-27 15:44:09 +08:00
李通洲 6423feaa94 Revert "OS (Windows): restores compatibility with WINE"
Seems WINE now has winbrand.dll

This reverts commit 554184ec72.
2026-02-27 15:41:55 +08:00
李通洲 92ada88ea7 WM (Windows): detect FancyWM & GlazeWM and their versions 2026-02-27 15:35:32 +08:00
李通洲 1789ef85d7 Processing (Windows): tidy 2026-02-27 15:04:43 +08:00
李通洲 42509f115c Common (Windows): always uses en_US when fetching exe version 2026-02-27 15:04:28 +08:00
李通洲 340a58bda1 Shell (Windows): ignore lldb-dap 2026-02-27 15:03:15 +08:00
李通洲 08dfd1321c Platform (macOS): use _NSGetExecutablePath to query current exe path
Unlike proc_pidpath which uses syscall
2026-02-26 15:12:53 +08:00
Carter Li 45d324a8c6 OpenGL: releases EGL context to avoid memleaks 2026-02-26 10:11:23 +08:00
Carter Li afa986efd4 Global (Linux): unrefs dbus replies to avoid memleaks 2026-02-26 10:11:12 +08:00
Carter Li bc6e8c7813 Global (Linux): unrefs dbus connection to avoid memleaks 2026-02-26 09:47:18 +08:00
Carter Li 627fee23d1 Chore: adds assertions 2026-02-26 09:00:24 +08:00
Carter Li 27b474f205 CPU: ensures tempSensor accepts string only
Fixes #2202
2026-02-26 08:55:53 +08:00
李通洲 418c7eecc7 Logo (Builtin): updates secureblue 2026-02-25 13:51:46 +08:00
李通洲 350250d640 Doc: updates json schema [ci skip] 2026-02-25 13:24:33 +08:00
Alxhr0 3cc21905af Editor: adds Zed version detection support (#2200) 2026-02-25 10:56:28 +08:00
underscorejoser c698eb8eb5 Logo (Builtin): fixes Fedora secureblue (#2201)
* fix: colored inside shackle

* Update ASCII art in secureblue.txt

* Fix formatting in secureblue.txt

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-02-25 10:55:47 +08:00
Carter Li 463c24beb8 WM (Linux): for LXQt, only query wm settings when wm was not detected
Fixes #2199
2026-02-25 10:37:18 +08:00
李通洲 a5d1b96ecc Logo (Builtin): update ArcoLinux entries to reflect discontinuation and simplify name list 2026-02-24 13:16:58 +08:00
李通洲 63106ebdc1 Logo (Builtin): simplify name entries for Artix and its variants 2026-02-24 12:59:52 +08:00
李通洲 fd36783adb Logo (Builtin): removes redundant name entry for Exherbo 2026-02-24 12:49:02 +08:00
李通洲 3b5186da53 Logo (Builtin): rename ExodiaPredator to ExodiaOS and simplify name entries 2026-02-24 12:48:31 +08:00
李通洲 0140a46090 Logo (Builtin): corrects name casing for Deepin and removes redundant entry 2026-02-24 12:18:04 +08:00
李通洲 9c38e1255f Logo (Builtin): remove redundant names for Debian and DebianSmall 2026-02-24 12:17:56 +08:00
李通洲 663f9d69ff Logo (Builtin): corrects spelling of LinuxLight to LinuxLite 2026-02-24 12:05:52 +08:00
李通洲 d12e5ab801 Logo (Builtin): tidy 2026-02-24 11:56:25 +08:00
李通洲 1d770d85f6 Logo (Builtin): simplifies MassOS name entry 2026-02-24 11:56:06 +08:00
李通洲 5b00afe45d Logo (Builtin): simplifies MiracleLinux name entry 2026-02-24 11:55:41 +08:00
李通洲 5b276567ac Logo (Builtin): simplifies MX and MXSmall name entries 2026-02-24 11:55:22 +08:00
李通洲 56566916e3 Logo (Builtin): simplifies Nobara name entries 2026-02-24 11:54:48 +08:00
李通洲 2c0b4ca3a2 Logo (Builtin): simplifies Raspbian name entries 2026-02-24 11:45:29 +08:00
李通洲 54ffdd32dc Logo (Builtin): simplifies RedOS name entries 2026-02-24 11:45:14 +08:00
李通洲 64f24bdee9 Logo (Builtin): renames Refracted Devuan to Refracta
Ref: https://github.com/dylanaraps/neofetch/issues/2338
2026-02-24 11:41:21 +08:00
李通洲 4706f97bf0 Logo (Builtin): simplifies Rocky Linux 2026-02-24 11:38:01 +08:00
李通洲 0bdb198d52 Logo (Builtin): updates RengeOS entry to remove redundant name 2026-02-24 11:02:11 +08:00
s0s fc7710821e Common: fixes segmentation fault triggered by dereferencing value at negative index (#2198) 2026-02-24 11:00:25 +08:00
thealio e22a9990ec Logo (Builtin): Aritx logos improvements (#2157)
* Create artix4.txt

* Rename artix4.txt to artix2.txt

* Rename artix_small.txt to artix1_small.txt

* Rename artix2_small.txt to artix_small.txt

* Rename artix1_small.txt to artix2_small.txt
2026-02-24 10:59:47 +08:00
Crystal_ForceIX fc7f3a1650 Logo (Builtin): adds RengeOS Logo (#2170) 2026-02-24 10:52:39 +08:00
Carter Li 915af9546d Keyboard (Linux): supports more keyboard events 2026-02-22 22:48:17 +08:00
Carter Li 54a68640ef Packages (Linux): supports moss
Fixes #2191
2026-02-22 22:33:27 +08:00
李通洲 ec1af7c92b Platform (OpenBSD): improves executable path retrieval method
Fixes #2195
2026-02-22 18:14:36 +08:00
Carter Li a1e20270ad Platform: add current working directory (cwd) to FFPlatform structure and initialization 2026-02-21 00:29:02 +08:00
Chiron 4996986ce6 Logo (Builtin): updates Linux Mint ASCII Logo (#2186) 2026-02-19 02:56:56 +08:00
李通洲 e6de2d4fd9 Doc: update issue template [ci skip] 2026-02-19 00:50:43 +08:00
李通洲 5347e74a1b Logo (Builtin): adds linuxmint2
Ref: #2186
2026-02-18 23:58:39 +08:00
李通洲 0ea5639a22 Platform (Windows): prefers Nt* APIs 2026-02-18 20:13:33 +08:00
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
519 changed files with 6856 additions and 3446 deletions
@@ -16,6 +16,15 @@ body:
options:
- label: I have checked the FAQ but the issue is not covered
required: true
- type: checkboxes
attributes:
label: Not a known issue
description: Please check if the issue is already known and being worked on.
options:
- label: I have checked the existing issues but the issue is not covered
required: true
- label: My issue is not about crashing on Fedora and KDE 6.6
required: true
- type: markdown
attributes:
value: "### General description of the bug"
+17 -10
View File
@@ -6,35 +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 contains no internal paddings (spaces at the start and the end of lines)
- 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.
+110 -55
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
@@ -93,16 +93,16 @@ jobs:
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 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
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 directx-headers-dev rpm ninja-build
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick --ignore-dependencies
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
- name: Initialize CodeQL
if: matrix.arch == 'amd64'
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: c
@@ -114,7 +114,7 @@ jobs:
- 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
@@ -151,7 +151,7 @@ jobs:
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
@@ -164,7 +164,7 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: uname -a
run: uname -a
@@ -217,7 +217,7 @@ jobs:
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-linux-i686
path: ./fastfetch-*.*
@@ -230,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
@@ -257,7 +257,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-linux-armv7l
path: ./fastfetch-*.*
@@ -270,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
@@ -293,7 +293,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-linux-armv6l
path: ./fastfetch-*.*
@@ -312,7 +312,7 @@ 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
@@ -336,7 +336,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
@@ -345,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
@@ -374,7 +374,7 @@ jobs:
shell: alpine.sh {0}
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
@@ -394,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
@@ -428,42 +428,80 @@ jobs:
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
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
with:
usesh: true
envs: 'CMAKE_BUILD_TYPE'
prepare: |
uname -a
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@v7
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
envs: 'CMAKE_BUILD_TYPE'
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@v7
with:
name: fastfetch-solaris-amd64
path: ./fastfetch-*.*
freebsd-amd64:
@@ -474,7 +512,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
@@ -483,7 +521,8 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '14.3'
version: '15.0'
environment_variables: 'CMAKE_BUILD_TYPE'
run: |
uname -a
sudo pkg update
@@ -498,7 +537,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-freebsd-amd64
path: ./fastfetch-*.*
@@ -511,7 +550,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
@@ -520,12 +559,13 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '7.7'
version: '7.8'
environment_variables: 'CMAKE_BUILD_TYPE'
run: |
uname -a
sudo pkg_add -u
sudo pkg_add -r llvm-19.1.7p3 cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
CC=clang-19 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
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
@@ -535,7 +575,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-openbsd-amd64
path: ./fastfetch-*.*
@@ -548,7 +588,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
@@ -558,6 +598,7 @@ jobs:
cpu_count: 4
shell: bash
version: '10.1'
environment_variables: 'CMAKE_BUILD_TYPE'
run: |
uname -a
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
@@ -571,7 +612,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-netbsd-amd64
path: ./fastfetch-*.*
@@ -584,12 +625,13 @@ jobs:
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: run VM
uses: vmactions/dragonflybsd-vm@v1
with:
usesh: yes
envs: 'CMAKE_BUILD_TYPE'
prepare: |
uname -a
pkg update
@@ -606,7 +648,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-dragonfly-amd64
path: ./fastfetch-*.*
@@ -619,7 +661,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
@@ -629,6 +671,7 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
environment_variables: 'CMAKE_BUILD_TYPE'
run: |
uname -a
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
@@ -641,13 +684,13 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
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
@@ -660,17 +703,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
@@ -683,7 +737,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
@@ -712,9 +766,9 @@ jobs:
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
id: upload-unsigned-artifact
name: upload artifacts for signing
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: fastfetch-windows-${{ matrix.arch }}
name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}
path: |
*.dll
fastfetch.exe
@@ -733,16 +787,16 @@ jobs:
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 true artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
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:
@@ -761,7 +815,8 @@ jobs:
- openbsd-amd64
- netbsd-amd64
- dragonfly-amd64
- sunos-amd64
- solaris-amd64
- omnios-amd64
- haiku-amd64
- windows-hosts
permissions:
@@ -775,7 +830,7 @@ jobs:
- name: download artifacts
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v5
uses: actions/download-artifact@v8
- name: create release
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
+145
View File
@@ -1,3 +1,148 @@
# 2.60.0
Changes:
* The CMake option `ENABLE_WIN7_COMPAT:BOOLEAN` now defaults to `OFF` and will be removed in v2.61.0, effectively dropping support for Windows 7 in the next release.
* This follows the Windows 7 deprecation notice introduced in v2.57.0.
* `wm.detectPlugin` now defaults to `true` (WM)
Features:
* Adds `{cwd}` for custom title formatting, which displays the current working directory (Title)
* Adds support for detecting the Zed version (#2200, Editor)
* Adds support for detecting `moss` packages (Packages, Linux)
* Adds support for detecting komorebi, FancyWM, and GlazeWM (WM, Windows)
* Adds support for WM plugin version detection on macOS (WM, macOS)
* Adds support for retrieving the executable path on OpenBSD (#2195, OpenBSD)
Bugfixes:
* Fixes a potential segmentation fault caused by dereferencing a negative index (#2198)
* Fixes `tempSensor` parsing so that it accepts only string values (#2202, CPU)
* Fixes an issue that unexpectedly caused fewer devices to be reported (Keyboard, Linux)
* Improves WM detection on LXQt by querying WM settings only when no WM has already been detected (#2199, WM, Linux)
* Fixes memory leaks in DBus connection handling and in the OpenGL EGL context lifecycle
* Fixes niri version detection on Fedora (WM, Linux)
* Includes various internal cleanups and optimizations
Logos:
* Adds `RengeOS` (#2170)
* Adds `Emmabuntüs` (#2207)
* Updates Artix Linux (#2157)
* Updates Linux Mint (#2186)
* Renames `Refracted Devuan` to `Refracta`
* Renames `ExodiaPredator` to `ExodiaOS`
# 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 issue 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:
+196 -135
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.56.0
VERSION 2.60.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -92,7 +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_PCIACCESS "Enable libpciaccess" ON "GNU" OFF)
option(ENABLE_ZLIB "Enable zlib" ON)
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
@@ -107,6 +106,12 @@ option(ENABLE_EMBEDDED_PCIIDS "Embed pci.ids into fastfetch, requires `python`"
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" OFF)
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")
@@ -161,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()
@@ -342,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()
####################
@@ -364,26 +375,32 @@ 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/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
@@ -452,6 +469,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
@@ -489,26 +507,22 @@ 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/common/impl/kmod_linux.c
src/detection/battery/battery_linux.c
src/detection/bios/bios_linux.c
src/detection/board/board_linux.c
@@ -583,16 +597,17 @@ if(LINUX)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_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/common/impl/kmod_linux.c
src/detection/battery/battery_android.c
src/detection/bios/bios_android.c
src/detection/bluetooth/bluetooth_nosupport.c
@@ -656,17 +671,18 @@ elseif(ANDROID)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_android.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/common/impl/kmod_bsd.c
src/detection/battery/battery_bsd.c
src/detection/bios/bios_bsd.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
@@ -738,8 +754,6 @@ elseif(FreeBSD)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
)
if(DragonFly)
list(APPEND LIBFASTFETCH_SRC
@@ -754,12 +768,15 @@ 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/common/impl/kmod_nbsd.c
src/detection/battery/battery_nbsd.c
src/detection/bios/bios_nbsd.c
src/detection/bluetooth/bluetooth_bsd.c
@@ -831,17 +848,19 @@ elseif(NetBSD)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_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/common/impl/kmod_nosupport.c
src/detection/battery/battery_obsd.c
src/detection/bios/bios_windows.c
src/detection/bluetooth/bluetooth_nosupport.c
@@ -913,17 +932,20 @@ elseif(OpenBSD)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.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/impl/kmod_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
@@ -982,18 +1004,24 @@ elseif(APPLE)
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_apple.m
src/detection/camera/camera_apple.m
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/impl/kmod_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/variant.cpp
src/common/windows/version.c
src/detection/battery/battery_windows.c
src/detection/bios/bios_windows.c
src/detection/bluetooth/bluetooth_windows.c
@@ -1032,7 +1060,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.cpp
src/detection/os/os_windows.c
src/detection/packages/packages_windows.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_windows.c
@@ -1047,27 +1075,21 @@ elseif(WIN32)
src/detection/users/users_windows.c
src/detection/wallpaper/wallpaper_windows.c
src/detection/wifi/wifi_windows.c
src/detection/wm/wm_windows.cpp
src/detection/wm/wm_windows.c
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_windows.c
src/detection/camera/camera_windows.cpp
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/common/impl/kmod_sunos.c
src/detection/battery/battery_nosupport.c
src/detection/bios/bios_windows.c
src/detection/board/board_windows.c
@@ -1139,16 +1161,18 @@ elseif(SunOS)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_nosupport.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/impl/kmod_nosupport.c
src/common/haiku/version.cpp
src/detection/battery/battery_haiku.c
src/detection/bios/bios_windows.c
src/detection/board/board_windows.c
@@ -1207,17 +1231,17 @@ elseif(Haiku)
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_nosupport.c
src/detection/camera/camera_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/common/impl/kmod_nosupport.c
src/detection/battery/battery_nosupport.c
src/detection/bios/bios_nosupport.c
src/detection/board/board_nosupport.c
@@ -1247,7 +1271,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_general.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
@@ -1286,8 +1310,6 @@ elseif(GNU)
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_nosupport.c
src/util/platform/FFPlatform_unix.c
src/util/binary_linux.c
)
endif()
@@ -1308,11 +1330,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)
@@ -1331,6 +1357,15 @@ 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=1)
target_link_libraries(libfastfetch PUBLIC yyjson::yyjson)
@@ -1402,7 +1437,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")
@@ -1410,9 +1445,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)
@@ -1598,10 +1663,6 @@ ff_lib_enable(DIRECTX_HEADERS
"DirectX-Headers"
"DirectX-Headers"
)
ff_lib_enable(PCIACCESS
"pciaccess"
"pciaccess"
)
if(ENABLE_THREADS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS=1)
@@ -1625,6 +1686,9 @@ if(ENABLE_LIBZFS)
)
endif()
endif()
if(NOT HAVE_MEMRCHR)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_CUSTOM_MEMRCHR=1)
endif()
if(LINUX)
target_link_libraries(libfastfetch
@@ -1661,7 +1725,6 @@ elseif(APPLE)
)
elseif(WIN32)
target_link_libraries(libfastfetch
PRIVATE "dwmapi"
PRIVATE "gdi32"
PRIVATE "iphlpapi"
PRIVATE "ole32"
@@ -1671,13 +1734,11 @@ elseif(WIN32)
PRIVATE "version"
PRIVATE "hid"
PRIVATE "wtsapi32"
PRIVATE "imagehlp"
PRIVATE "cfgmgr32"
PRIVATE "propsys"
PRIVATE "winbrand"
PRIVATE "secur32"
)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
# WoA only works on Windows 10 or higher
if(NOT ENABLE_WIN7_COMPAT)
target_link_libraries(libfastfetch
PRIVATE "mincore"
)
@@ -1865,7 +1926,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
@@ -1893,7 +1954,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
@@ -2058,7 +2119,7 @@ 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()
+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
+1 -1
View File
@@ -13,7 +13,7 @@
[![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 and SunOS (illumos, 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" />
+30
View File
@@ -1,3 +1,33 @@
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
+33 -14
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. {moss}: Number of moss packages\n 45. {nix-all}: Total number of all nix packages\n 46. {flatpak-all}: Total number of all flatpak app packages\n 47. {brew-all}: Total number of all brew packages\n 48. {guix-all}: Total number of all guix packages\n 49. {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\n 12. {cwd}: CWD with home dir replaced by `~`",
"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"
}
},
@@ -1521,7 +1521,7 @@
"description": "Print battery capacity, status, etc"
},
"useSetupApi": {
"description": "Set if `SetupAPI` should be used on Windows to detect battery info, which supports multi batteries, but slower. Windows only",
"description": "Set if `CM API` should be used on Windows to detect battery info, which supports multi batteries, but slower. Windows only",
"type": "boolean",
"default": false
},
@@ -1880,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",
@@ -1995,7 +1999,7 @@
"additionalProperties": false,
"properties": {
"type": {
"description": "Print some colored blocks",
"description": "Display the terminal's 16-color palette",
"const": "colors"
},
"symbol": {
@@ -2514,11 +2518,6 @@
"const": "de",
"description": "Print desktop environment name"
},
"slowVersionDetection": {
"type": "boolean",
"description": "Set if DE version should be detected with slow operations.\nShould be unnecessary for most cases.\nThis is only used as a fallback method. Please file a bug report if you encounter any issues.",
"default": false
},
"key": {
"$ref": "#/$defs/key"
},
@@ -2960,8 +2959,11 @@
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"outputColor": {
"$ref": "#/$defs/outputColor"
},
"format": {
"$ref": "#/$defs/memoryFormat"
"$ref": "#/$defs/keyboardFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
@@ -3195,6 +3197,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",
@@ -3292,8 +3308,11 @@
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"outputColor": {
"$ref": "#/$defs/outputColor"
},
"format": {
"$ref": "#/$defs/memoryFormat"
"$ref": "#/$defs/mouseFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
@@ -4463,7 +4482,7 @@
"detectPlugin": {
"description": "Set if window manager plugin should be detected on supported platforms",
"type": "boolean",
"default": false
"default": true
},
"key": {
"$ref": "#/$defs/key"
+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.
{
+51 -50
View File
@@ -9,25 +9,26 @@
// Constants are reusable strings referenced by {$1}, {$2}, etc.
// These contain ANSI escape codes for cursor positioning
"constants": [
"──────────────────────────────────────────────", // {$1} - horizontal line for borders
"──────────────────────────────────────────────", // {$1} - horizontal line for inner borders
"\u001b[47D", // {$2} - move cursor left 47 columns
"\u001b[47C", // {$3} - move cursor right 47 columns
"\u001b[46C" // {$4} - move cursor right 46 columns
"\u001b[46C", // {$4} - move cursor right 46 columns
"══════════════════════════════════════════════" // {$5} - horizontal line for outer borders
],
"brightColor": false
},
"modules": [
{
"type": "version",
"key": "┌───────────────┬─{$1}┐\u001b[41D",
"key": "╔═══════════════╦═{$5}╗\u001b[41D",
"format": "\u001b[1m{#keys} {1} - {2} "
},
{
"type": "os",
// Key format breakdown for OS module:
// " {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}{$2}"
// " {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}{$2}"
//
// - Left border of key block
// - Left border of key block
// {icon} - OS icon (defined internally by fastfetch)
// \u001b[s - ANSI escape: save cursor position (ESC[s)
// {sysname} - Format variable: system name (e.g., "Linux", "Darwin")
@@ -36,28 +37,28 @@
// \u001b[10C - ANSI escape: move cursor right 10 columns (ESC[10C)
// │ - Right border of key block (always 10 columns from left border)
// {$3} - Reference to constants[2]: move cursor right 47 columns
// - Right border of value block
// - Right border of value block
// {$2} - Reference to constants[1]: move cursor left 47 columns
//
// This creates a fixed-width layout where the key block is exactly 10 columns wide,
// regardless of the actual content length. The cursor manipulation ensures proper
// alignment for the table-like structure.
"key": " {icon} \u001b[s{sysname}\u001b[u\u001b[10C{$3}{$2}"
"key": " {icon} \u001b[s{sysname}\u001b[u\u001b[10C{$3}{$2}"
},
{
"type": "datetime",
"key": " {icon} Fetched {$3}{$2}",
"key": " {icon} Fetched {$3}{$2}",
"format": "{year}-{month-pretty}-{day-pretty} {hour-pretty}:{minute-pretty}:{second-pretty} {timezone-name}"
},
{
"type": "locale",
"key": " {icon} Locale {$3}{$2}"
"key": " {icon} Locale {$3}{$2}"
},
// Hardware section with cyan color theme
{
"type": "custom",
"key": "{#cyan}┌──────────────┬{$1}┐{#keys}\u001b[37D",
"key": "{#cyan}┌──────────────┬{$1}┐{#keys}\u001b[37D",
"format": "{#bright_cyan} Hardware "
},
{
@@ -66,113 +67,113 @@
// │{#cyan}│ - Left border with cyan color
// {icon} - Chassis icon
// Chassis - Fixed label text
// │{$4}│{#keys}{$2} - Positioning and borders for value area
"key": "{#cyan}│ {icon} Chassis │{$4}│{#keys}{$2}"
// │{$4}│{#keys}{$2} - Positioning and borders for value area
"key": "{#cyan}│ {icon} Chassis │{$4}│{#keys}{$2}"
},
{
"type": "memory",
"key": "{#cyan}│ {icon} RAM │{$4}│{#keys}{$2}"
"key": "{#cyan}│ {icon} RAM │{$4}│{#keys}{$2}"
},
{
"type": "swap",
"key": "{#cyan}│ {icon} SWAP │{$4}│{#keys}{$2}"
"key": "{#cyan}│ {icon} SWAP │{$4}│{#keys}{$2}"
},
{
"type": "cpu",
"key": "{#cyan}│ {icon} CPU │{$4}│{#keys}{$2}",
"key": "{#cyan}│ {icon} CPU │{$4}│{#keys}{$2}",
"showPeCoreCount": true
},
{
"type": "gpu",
"key": "{#cyan}│ {icon} GPU │{$4}│{#keys}{$2}"
"key": "{#cyan}│ {icon} GPU │{$4}│{#keys}{$2}"
},
{
"type": "disk",
"key": "{#cyan}│ {icon} Disk │{$4}│{#keys}{$2}",
"key": "{#cyan}│ {icon} Disk │{$4}│{#keys}{$2}",
"format": "{size-used} \/ {size-total} ({size-percentage}) - {filesystem}",
},
{
"type": "battery",
"key": "{#cyan}│ {icon} Battery │{$4}│{#keys}{$2}"
"key": "{#cyan}│ {icon} Battery │{$4}│{#keys}{$2}"
},
{
"type": "custom",
"key": "{#cyan}└──────────────┴{$1}┘{#keys}",
"key": "{#cyan}└──────────────┴{$1}┘{#keys}",
"format": ""
},
// Desktop section with green color theme
{
"type": "custom",
"key": "{#green}┌──────────────┬{$1}┐{#keys}\u001b[37D",
"key": "{#green}┌──────────────┬{$1}┐{#keys}\u001b[37D",
"format": "{#bright_green} Desktop "
},
{
"type": "de",
"key": "{#green}│ {icon} Desktop │{$4}│{#keys}{$2}"
"key": "{#green}│ {icon} Desktop │{$4}│{#keys}{$2}"
},
{
"type": "wm",
"key": "{#green}│ {icon} Session │{$4}│{#keys}{$2}"
"key": "{#green}│ {icon} Session │{$4}│{#keys}{$2}"
},
{
"type": "display",
"key": "{#green}│ {icon} Display │{$4}│{#keys}{$2}",
"key": "{#green}│ {icon} Display │{$4}│{#keys}{$2}",
"compactType": "original-with-refresh-rate"
},
{
"type": "gpu",
"key": "{#green}│ {icon} G-Driver │{$4}│{#keys}{$2}",
"key": "{#green}│ {icon} G-Driver │{$4}│{#keys}{$2}",
"format": "{driver}"
},
{
"type": "custom",
"key": "{#green}└──────────────┴{$1}┘{#keys}",
"key": "{#green}└──────────────┴{$1}┘{#keys}",
"format": ""
},
// Terminal section with yellow color theme
{
"type": "custom",
"key": "{#yellow}┌──────────────┬{$1}┐{#keys}\u001b[37D",
"key": "{#yellow}┌──────────────┬{$1}┐{#keys}\u001b[37D",
"format": "{#bright_yellow} Terminal "
},
{
"type": "shell",
"key": "{#yellow}│ {icon} Shell │{$4}│{#keys}{$2}"
"key": "{#yellow}│ {icon} Shell │{$4}│{#keys}{$2}"
},
{
"type": "terminal",
"key": "{#yellow}│ {icon} Terminal │{$4}│{#keys}{$2}"
"key": "{#yellow}│ {icon} Terminal │{$4}│{#keys}{$2}"
},
{
"type": "terminalfont",
"key": "{#yellow}│ {icon} Term Font │{$4}│{#keys}{$2}"
"key": "{#yellow}│ {icon} Term Font │{$4}│{#keys}{$2}"
},
{
"type": "terminaltheme",
"key": "{#yellow}│ {icon} Colors │{$4}│{#keys}{$2}"
"key": "{#yellow}│ {icon} Colors │{$4}│{#keys}{$2}"
},
{
"type": "packages",
"key": "{#yellow}│ {icon} Packages │{$4}│{#keys}{$2}"
"key": "{#yellow}│ {icon} Packages │{$4}│{#keys}{$2}"
},
{
"type": "custom",
"key": "{#yellow}└──────────────┴{$1}┘{#keys}",
"key": "{#yellow}└──────────────┴{$1}┘{#keys}",
"format": ""
},
// Development section with red color theme
{
"type": "custom",
"key": "{#red}┌──────────────┬{$1}┐{#keys}\u001b[39D",
"key": "{#red}┌──────────────┬{$1}┐{#keys}\u001b[39D",
"format": "{#bright_red} Development "
},
{
"type": "command",
"keyIcon": "", // Custom icon override
"key": "{#red}│ {icon} Rust │{$4}│{#keys}{$2}",
"key": "{#red}│ {icon} Rust │{$4}│{#keys}{$2}",
"text": "rustc --version",
"format": "rustc {~6,13}" // Print 6th to 13th characters (version number)
},
@@ -182,7 +183,7 @@
"!system": "Windows" // Posix version
},
"keyIcon": "",
"key": "{#red}│ {icon} Clang │{$4}│{#keys}{$2}",
"key": "{#red}│ {icon} Clang │{$4}│{#keys}{$2}",
"text": "clang --version | sed -n 's/.*version \\([0-9][0-9.]*\\).*/\\1/p'",
"format": "clang {}"
},
@@ -192,67 +193,67 @@
"system": "Windows" // Windows version
},
"keyIcon": "",
"key": "{#red}│ {icon} Clang │{$4}│{#keys}{$2}",
"key": "{#red}│ {icon} Clang │{$4}│{#keys}{$2}",
"text": "clang --version | findstr version", // Finds the line with "version"
"format": "clang {~-6}" // Prints the last 6 characters (version number)
},
{
"type": "command",
"keyIcon": "",
"key": "{#red}│ {icon} NodeJS │{$4}│{#keys}{$2}",
"key": "{#red}│ {icon} NodeJS │{$4}│{#keys}{$2}",
"text": "node --version",
"format": "node {~1}" // {~1} removes first character (v)
},
{
"type": "command",
"keyIcon": "",
"key": "{#red}│ {icon} Go │{$4}│{#keys}{$2}",
"key": "{#red}│ {icon} Go │{$4}│{#keys}{$2}",
"text": "go version | cut -d' ' -f3",
"format": "go {~2}" // {~2} removes first 2 characters (go)
},
{
"type": "command",
"keyIcon": "",
"key": "{#red}│ {icon} Zig │{$4}│{#keys}{$2}",
"key": "{#red}│ {icon} Zig │{$4}│{#keys}{$2}",
"text": "zig version",
"format": "zig {}"
},
{
"type": "editor",
"key": "{#red}│ {icon} Editor │{$4}│{#keys}{$2}"
"key": "{#red}│ {icon} Editor │{$4}│{#keys}{$2}"
},
{
"type": "command",
"keyIcon": "󰊢",
"key": "{#red}│ {icon} Git │{$4}│{#keys}{$2}",
"key": "{#red}│ {icon} Git │{$4}│{#keys}{$2}",
"text": "git version",
"format": "git {~12}"
},
{
"type": "font",
"key": "{#red}│ {icon} Interface │{$4}│{#keys}{$2}"
"key": "{#red}│ {icon} Interface │{$4}│{#keys}{$2}"
},
{
"type": "custom",
"key": "{#red}└──────────────┴{$1}┘{#keys}",
"key": "{#red}└──────────────┴{$1}┘{#keys}",
"format": ""
},
// Uptime section with magenta color theme
{
"type": "custom",
"key": "{#magenta}┌──────────────┬{$1}┐{#keys}\u001b[36D",
"key": "{#magenta}┌──────────────┬{$1}┐{#keys}\u001b[36D",
"format": "{#bright_magenta} Uptime "
},
{
"type": "uptime",
"key": "{#magenta}│ {icon} Uptime │{$4}│{#keys}{$2}"
"key": "{#magenta}│ {icon} Uptime │{$4}│{#keys}{$2}"
},
{
"type": "users",
"myselfOnly": true, // Only show current user
"keyIcon": "",
"key": "{#magenta}│ {icon} Login │{$4}│{#keys}{$2}"
"key": "{#magenta}│ {icon} Login │{$4}│{#keys}{$2}"
},
{
"condition": { // Conditional module: only show on non-macOS
@@ -260,7 +261,7 @@
},
"type": "disk",
"keyIcon": "",
"key": "{#magenta}│ {icon} OS Age │{$4}│{#keys}{$2}",
"key": "{#magenta}│ {icon} OS Age │{$4}│{#keys}{$2}",
"folders": "/", // Check root filesystem
"format": "{create-time:10} [{days} days]" // Show creation time and age in days
},
@@ -270,18 +271,18 @@
},
"type": "disk",
"keyIcon": "",
"key": "{#magenta}│ {icon} OS Age │{$4}│{#keys}{$2}",
"key": "{#magenta}│ {icon} OS Age │{$4}│{#keys}{$2}",
"folders": "/System/Volumes/VM", // Work around for APFS on macOS
"format": "{create-time:10} [{days} days]"
},
{
"type": "custom",
"key": "{#magenta}└──────────────┴{$1}┘{#keys}",
"key": "{#magenta}└──────────────┴{$1}┘{#keys}",
"format": ""
},
{
"type": "custom",
"key": "└─────────────────{$1}┘", // Bottom border of the entire layout
"key": "╚═════════════════{$5}╝", // Bottom border of the entire layout
"format": ""
},
+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
+57
View File
@@ -0,0 +1,57 @@
// Inspired by microfetch
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "small"
},
"general": {
"detectVersion": false
},
"display": {
"separator": "  ",
"brightColor": false,
"key": {
"type": "both-2"
}
},
"modules": [
{
"type": "title",
"format": "{user-name-colored}{#light_red}@{host-name-colored} {#}{cwd}"
},
{
"type": "os",
"key": "System "
},
{
"type": "kernel",
"key": "Kernel "
},
{
"type": "shell",
"key": "Shell "
},
{
"type": "uptime",
"key": "Uptime "
},
{
"type": "wm",
"key": "Desktop "
},
{
"type": "memory",
"key": "Memory "
},
{
"type": "disk",
"key": "Storage (/) ",
"folders": "/"
},
{
"type": "colors",
"key": "Colors ",
"symbol": "circle"
}
]
}
+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
{
@@ -18,8 +18,15 @@ 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)
FFstrbuf cwd; // Trailing slash included
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)); \
})
+58 -55
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,6 +103,10 @@ FF_C_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultV
void ffStrbufUpperCase(FFstrbuf* strbuf);
void ffStrbufLowerCase(FFstrbuf* strbuf);
// 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);
@@ -104,10 +115,14 @@ void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, 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] 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.
* @param[in] buffer The buffer to read from. The buffer must not be a string literal.
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.
*/
@@ -117,7 +132,7 @@ static inline bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
}
/**
* @brief Restore the end of a line that was modified by ffStrbufGetline.
* @warning This function should be called before breaking an ffStrbufGetline loop.
* @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)
{
@@ -147,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);
@@ -167,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
@@ -212,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)
@@ -243,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)
@@ -260,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;
}
@@ -326,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)
@@ -386,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);
@@ -1,6 +1,6 @@
#include "smc_temps.h"
#include "util/apple/cf_helpers.h"
#include "util/stringUtils.h"
#include "common/apple/cf_helpers.h"
#include "common/stringUtils.h"
#include <stdint.h>
#include <math.h>
@@ -156,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;
}
@@ -277,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);
+5 -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
@@ -19,6 +19,7 @@ typedef struct FFDBusLibrary
FF_LIBRARY_SYMBOL(dbus_message_iter_next)
FF_LIBRARY_SYMBOL(dbus_message_unref)
FF_LIBRARY_SYMBOL(dbus_connection_send_with_reply_and_block)
FF_LIBRARY_SYMBOL(dbus_connection_unref)
} FFDBusLibrary;
typedef struct FFDBusData
@@ -36,10 +37,13 @@ DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
void ffDBusDestroyData(FFDBusData* data);
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface)
{
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, NULL);
}
#define FF_DBUS_AUTO_DESTROY_DATA __attribute__((__cleanup__(ffDBusDestroyData)))
#endif // FF_HAVE_DBUS
+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;
-238
View File
@@ -1,238 +0,0 @@
#include "fastfetch.h"
#include "util/FFlist.h"
#include "util/FFstrbuf.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 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);
}
+4 -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,8 @@ 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)
@@ -10,12 +10,17 @@ void ffPlatformInit(FFPlatform* platform)
ffListInit(&platform->configDirs, sizeof(FFstrbuf));
ffListInit(&platform->dataDirs, sizeof(FFstrbuf));
ffStrbufInit(&platform->exePath);
ffStrbufInit(&platform->cwd);
ffStrbufInit(&platform->userName);
ffStrbufInit(&platform->fullUserName);
ffStrbufInit(&platform->hostName);
ffStrbufInit(&platform->userShell);
#ifdef _WIN32
ffStrbufInit(&platform->sid);
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
ffStrbufInit(&info->name);
@@ -45,12 +50,17 @@ void ffPlatformDestroy(FFPlatform* platform)
ffStrbufDestroy(dir);
ffListDestroy(&platform->dataDirs);
ffStrbufDestroy(&platform->exePath);
ffStrbufDestroy(&platform->cwd);
ffStrbufDestroy(&platform->userName);
ffStrbufDestroy(&platform->hostName);
ffStrbufDestroy(&platform->userShell);
ffStrbufDestroy(&platform->fullUserName);
#ifdef _WIN32
ffStrbufDestroy(&platform->sid);
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
ffStrbufDestroy(&info->architecture);
ffStrbufDestroy(&info->name);
@@ -1,6 +1,6 @@
#pragma once
#include "FFPlatform.h"
#include "common/FFPlatform.h"
void ffPlatformInitImpl(FFPlatform* platform);
@@ -1,8 +1,9 @@
#include "FFPlatform_private.h"
#include "util/FFstrbuf.h"
#include "util/stringUtils.h"
#include "common/FFstrbuf.h"
#include "common/arrayUtils.h"
#include "common/stringUtils.h"
#include "common/io.h"
#include "fastfetch_config.h"
#include "common/io/io.h"
#include <unistd.h>
#include <pwd.h>
@@ -11,10 +12,14 @@
#include <paths.h>
#ifdef __APPLE__
#include <libproc.h>
#include <mach-o/dyld.h>
#include <sys/sysctl.h>
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#elif defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/sysctl.h>
#elif defined(__OpenBSD__)
#include <sys/sysctl.h>
#include <kvm.h>
#include "common/path.h"
#elif defined(__HAIKU__)
#include <image.h>
#include <OS.h>
@@ -22,21 +27,25 @@
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));
uint32_t exePathLen = sizeof(exePath);
if (_NSGetExecutablePath(exePath, &exePathLen) == 0)
exePathLen = (uint32_t) strlen(exePath);
else
exePathLen = 0;
#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,
@@ -46,7 +55,81 @@ static void getExePath(FFPlatform* platform)
else
exePathLen--; // remove terminating NUL
#elif defined(__OpenBSD__)
// OpenBSD doesn't have a reliable way to get the executable path.
// Current implementation uses argv[0], which can be easily spoofed.
// See #2195
size_t exePathLen = 0;
kvm_t* kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
if (kd)
{
int kpCount;
struct kinfo_proc* kp = kvm_getprocs(kd, KERN_PROC_PID, (pid_t) platform->pid, sizeof(*kp), &kpCount);
if (kp && kpCount == 1)
{
char** argv = kvm_getargv(kd, kp, 0);
if (argv && argv[0])
{
char* arg0 = argv[0];
if (arg0[0])
{
if (strchr(arg0, '/') != NULL) // likely a path (absolute or relative)
{
exePathLen = strlen(arg0);
if (exePathLen < ARRAY_SIZE(exePath))
{
memcpy(exePath, arg0, exePathLen);
exePath[exePathLen] = '\0';
}
else
exePathLen = 0;
}
else
{
FF_STRBUF_AUTO_DESTROY tmpPath = ffStrbufCreate();
if (ffFindExecutableInPath(arg0, &tmpPath) == NULL && tmpPath.length < ARRAY_SIZE(exePath))
{
memcpy(exePath, tmpPath.chars, tmpPath.length + 1);
exePathLen = tmpPath.length;
}
}
if (exePathLen > 0)
{
struct stat st;
if (stat(exePath, &st) == 0 && S_ISREG(st.st_mode))
{
int cntp;
struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, platform->pid, sizeof(*kf), &cntp);
if (kf)
{
int i;
for (i = 0; i < cntp; i++)
{
if (kf[i].fd_fd == KERN_FILE_TEXT)
{
// KERN_FILE_TEXT is the executable file, not a shared library, and should be unique in the list.
if (st.st_dev != (dev_t)kf[i].va_fsid || st.st_ino != (ino_t)kf[i].va_fileid)
i = -1;
break;
}
}
if (i < 0)
exePathLen = 0;
}
else
{
// If we can't get the list of open files, we can't verify that the file is actually the executable
// Assume it is
}
}
else
exePathLen = 0;
}
}
}
}
kvm_close(kd);
}
#elif defined(__sun)
ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1);
if (exePathLen >= 0)
@@ -58,7 +141,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;
}
}
@@ -177,17 +260,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);
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)
@@ -225,15 +307,28 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts)
#endif
}
static void getCwd(FFPlatform* platform)
{
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) != NULL)
{
ffStrbufSetS(&platform->cwd, cwd);
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
}
}
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)
memset(&uts, 0, sizeof(uts));
getExePath(platform);
getCwd(platform);
getHomeDir(platform, pwd);
getCacheDir(platform);
getConfigDirs(platform);
@@ -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 <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,36 +138,62 @@ 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 const char* detectWine(void)
@@ -180,10 +208,6 @@ static const char* detectWine(void)
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
{
RTL_OSVERSIONINFOW osVersion = { .dwOSVersionInfoSize = sizeof(osVersion) };
if (!NT_SUCCESS(RtlGetVersion(&osVersion)))
return;
FF_HKEY_AUTO_DESTROY hKey = NULL;
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL))
return;
@@ -193,40 +217,41 @@ static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
ffStrbufAppendF(&info->release,
"%u.%u.%u.%u",
(unsigned) osVersion.dwMajorVersion,
(unsigned) osVersion.dwMinorVersion,
(unsigned) osVersion.dwBuildNumber,
(unsigned) SharedUserData->NtMajorVersion,
(unsigned) SharedUserData->NtMinorVersion,
(unsigned) SharedUserData->NtBuildNumber,
(unsigned) ubr);
ffRegReadStrbuf(hKey, L"BuildLabEx", &info->version, NULL);
const char* wineVersion = detectWine();
if (wineVersion)
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
else
{
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;
}
if (instance.config.general.detectVersion)
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
else
ffStrbufSetStatic(&info->name, "Wine");
}
else
ffStrbufSetStatic(&info->name, "WIN32_NT");
}
static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
static void getSystemPageSize(FFPlatformSysinfo* info)
{
SYSTEM_INFO sysInfo;
GetNativeSystemInfo(&sysInfo);
SYSTEM_BASIC_INFORMATION sbi;
if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL)))
info->pageSize = sbi.PhysicalPageSize;
else
info->pageSize = 4096;
}
switch(sysInfo.wProcessorArchitecture)
static void getSystemArchitecture(FFPlatformSysinfo* info)
{
SYSTEM_PROCESSOR_INFORMATION spi;
if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorInformation, &spi, sizeof(spi), NULL)))
{
switch (spi.ProcessorArchitecture)
{
case PROCESSOR_ARCHITECTURE_AMD64:
ffStrbufSetStatic(&info->architecture, "x86_64");
break;
@@ -234,7 +259,7 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
ffStrbufSetStatic(&info->architecture, "ia64");
break;
case PROCESSOR_ARCHITECTURE_INTEL:
switch (sysInfo.wProcessorLevel)
switch (spi.ProcessorLevel)
{
case 4:
ffStrbufSetStatic(&info->architecture, "i486");
@@ -272,14 +297,28 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
default:
ffStrbufSetStatic(&info->architecture, "unknown");
break;
}
}
}
info->pageSize = sysInfo.dwPageSize;
static void getCwd(FFPlatform* platform)
{
#if _WIN64
static_assert(
offsetof(RTL_USER_PROCESS_PARAMETERS, Reserved2[5]) == 0x38,
"CurrentDirectory should be at offset 0x38 in RTL_USER_PROCESS_PARAMETERS. Structure layout mismatch detected.");
#endif
PCURDIR cwd = (PCURDIR) &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->Reserved2[5];
ffStrbufSetNWS(&platform->cwd, cwd->DosPath.Length / sizeof(WCHAR), cwd->DosPath.Buffer);
ffStrbufReplaceAllC(&platform->cwd, '\\', '/');
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
}
void ffPlatformInitImpl(FFPlatform* platform)
{
platform->pid = (uint32_t) GetCurrentProcessId();
getExePath(platform);
getCwd(platform);
getHomeDir(platform);
getCacheDir(platform);
getConfigDirs(platform);
@@ -290,5 +329,6 @@ void ffPlatformInitImpl(FFPlatform* platform)
getUserShell(platform);
getSystemReleaseAndVersion(&platform->sysinfo);
getSystemArchitectureAndPageSize(&platform->sysinfo);
getSystemArchitecture(&platform->sysinfo);
getSystemPageSize(&platform->sysinfo);
}
@@ -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;
}
@@ -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,10 +1,9 @@
#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/windows/nt.h"
#include <windows.h>
#include <imagehlp.h>
#include <stdlib.h>
#include <string.h>
@@ -17,19 +16,33 @@
*/
const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
{
// Use MapAndLoad with cleanup attribute to ensure proper unloading
__attribute__((__cleanup__(UnMapAndLoad))) LOADED_IMAGE loadedImage = {};
if (!MapAndLoad(peFile, NULL, &loadedImage, FALSE, TRUE))
return "File could not be loaded";
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileA(peFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return "CreateFileA() failed";
// Iterate through all sections in the PE file
for (ULONG i = 0; i < loadedImage.NumberOfSections; ++i)
FF_AUTO_CLOSE_FD HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMap)
return "CreateFileMappingW() failed";
void* base = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if (!base)
return "MapViewOfFile() failed";
PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader(base);
if (!ntHeaders)
{
UnmapViewOfFile(base);
return "RtlImageNtHeader() failed";
}
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section)
{
PIMAGE_SECTION_HEADER section = &loadedImage.Sections[i];
// Look for initialized data sections with the name ".rdata" which typically contains string literals
if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) && ffStrEquals((const char*) section->Name, ".rdata"))
{
uint8_t *data = (uint8_t *) loadedImage.MappedAddress + section->PointerToRawData;
uint8_t *data = (uint8_t *) base + section->PointerToRawData;
// Scan the section for string literals
for (size_t off = 0; off < section->SizeOfRawData; ++off)
@@ -48,5 +61,6 @@ const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *st
}
}
UnmapViewOfFile(base);
return NULL;
}
@@ -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);
}
}
+12 -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)
{
@@ -19,6 +19,7 @@ static bool loadLibSymbols(FFDBusLibrary* lib)
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_next, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_unref, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_send_with_reply_and_block, false)
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_unref, false)
dbus = NULL; // don't auto dlclose
return true;
}
@@ -51,6 +52,15 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data)
return NULL;
}
void ffDBusDestroyData(FFDBusData* data)
{
if (data->connection != NULL)
{
data->lib->ffdbus_connection_unref(data->connection);
data->connection = NULL;
}
}
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
{
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
@@ -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>
@@ -87,7 +87,7 @@ static uint32_t getArgumentIndex(const char* placeholderValue, uint32_t numArgs,
for (uint32_t i = 0; i < numArgs; ++i)
{
const FFformatarg* arg = &arguments[i];
if (arg->name && strcasecmp(placeholderValue, arg->name) == 0)
if (arg->name && ffStrEqualsIgnCase(placeholderValue, arg->name))
return i + 1;
}
}
@@ -204,7 +204,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
// testing for an invalid index
if (index > numArgs)
if (index > numArgs || index < 1)
{
appendInvalidPlaceholder(buffer, "{?", &placeholderValue, i, formatstr->length);
continue;
@@ -230,7 +230,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
// testing for an invalid index
if (index > numArgs)
if (index > numArgs || index < 1)
{
appendInvalidPlaceholder(buffer, "{/", &placeholderValue, i, formatstr->length);
continue;
@@ -1,4 +1,4 @@
#include "frequency.h"
#include "common/frequency.h"
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result)
{
+11 -15
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,6 @@ static void initState(FFstate* state)
state->titleFqdn = false;
ffPlatformInit(&state->platform);
state->configDoc = NULL;
state->resultDoc = NULL;
state->dynamicInterval = 0;
{
@@ -96,8 +94,8 @@ static void exitSignalHandler(FF_MAYBE_UNUSED int signal)
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);
@@ -124,7 +122,7 @@ void ffStart(void)
#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)
@@ -138,8 +136,6 @@ void ffStart(void)
fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer
fflush(stdout);
}
ffLogoPrint();
}
void ffFinish(void)
@@ -157,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)
@@ -232,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
@@ -262,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>
@@ -23,7 +23,7 @@ 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);
@@ -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);
@@ -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>
@@ -230,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))
@@ -298,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
@@ -329,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)
+13
View File
@@ -0,0 +1,13 @@
#include "common/kmod.h"
#include "common/apple/cf_helpers.h"
#include <IOKit/kext/KextManager.h>
#include <CoreFoundation/CoreFoundation.h>
bool ffKmodLoaded(const char* modName)
{
FF_CFTYPE_AUTO_RELEASE CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, modName, kCFStringEncodingUTF8);
FF_CFTYPE_AUTO_RELEASE CFArrayRef identifiers = CFArrayCreate(kCFAllocatorDefault, (const void**) &name, 1, &kCFTypeArrayCallBacks);
FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL);
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef kextInfo = KextManagerCopyLoadedKextInfo(identifiers, keys);
return CFDictionaryContainsKey(kextInfo, name);
}
+8
View File
@@ -0,0 +1,8 @@
#include "common/kmod.h"
#include <sys/param.h>
#include <sys/module.h>
bool ffKmodLoaded(const char* modName)
{
return modfind(modName) >= 0;
}
+23
View File
@@ -0,0 +1,23 @@
#include "common/kmod.h"
#include "common/io.h"
bool ffKmodLoaded(const char* modName)
{
static FFstrbuf modules;
if (modules.chars == NULL)
{
ffStrbufInitS(&modules, "\n");
ffAppendFileBuffer("/proc/modules", &modules);
}
if (modules.length == 0) return false;
uint32_t len = (uint32_t) strlen(modName);
if (len > 250) return false;
char temp[256];
temp[0] = '\n';
memcpy(temp + 1, modName, len);
temp[1 + len] = ' ';
return memmem(modules.chars, modules.length, temp, len + 2) != NULL;
}
+43
View File
@@ -0,0 +1,43 @@
#include "common/kmod.h"
#include "common/stringUtils.h"
#include <sys/module.h>
#include <sys/param.h>
typedef struct __attribute__((__packed__)) FFNbsdModList
{
int len;
modstat_t mods[];
} FFNbsdModList;
bool ffKmodLoaded(const char* modName)
{
static FFNbsdModList* list = NULL;
if (list == NULL)
{
struct iovec iov = {};
for (size_t len = 8192;; len = iov.iov_len)
{
iov.iov_len = len;
iov.iov_base = realloc(iov.iov_base, len);
if (modctl(MODCTL_STAT, &iov) < 0)
{
free(iov.iov_base);
return true; // ignore errors
}
if (len >= iov.iov_len) break;
}
list = (FFNbsdModList*) iov.iov_base;
}
for (int i = 0; i < list->len; i++)
{
if (ffStrEquals(list->mods[i].ms_name, modName))
return true;
}
return false;
}
+6
View File
@@ -0,0 +1,6 @@
#include "common/kmod.h"
bool ffKmodLoaded(FF_MAYBE_UNUSED const char* modName)
{
return true; // Don't generate kernel module related errors
}
+24
View File
@@ -0,0 +1,24 @@
#include "common/kmod.h"
#include "common/stringUtils.h"
#include <sys/modctl.h>
#include <errno.h>
bool ffKmodLoaded(const char* modName)
{
struct modinfo modinfo = {
.mi_id = -1,
.mi_nextid = -1,
.mi_info = MI_INFO_ALL,
};
for (int id = -1; modctl(MODINFO, id, &modinfo) == 0; id = modinfo.mi_id)
{
modinfo.mi_name[MODMAXNAMELEN - 1] = '\0';
if (ffStrEquals(modinfo.mi_name, modName))
return true;
}
return !(errno == EINVAL || errno == ENOENT);
}
+27
View File
@@ -0,0 +1,27 @@
#include "common/kmod.h"
#include "common/windows/nt.h"
#include "common/mallocHelper.h"
#include "common/stringUtils.h"
bool ffKmodLoaded(const char* modName)
{
ULONG bufferSize = 0;
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &bufferSize);
if (bufferSize == 0)
return true; // ignore errors
FF_AUTO_FREE RTL_PROCESS_MODULES* buffer = malloc(bufferSize);
if (!NT_SUCCESS(NtQuerySystemInformation(SystemModuleInformation, buffer, bufferSize, &bufferSize)))
return true; // ignore errors
for (ULONG i = 0; i < buffer->NumberOfModules; i++)
{
const char* name = (const char*) buffer->Modules[i].FullPathName + buffer->Modules[i].OffsetToFileName;
if (ffStrEqualsIgnCase(name, modName))
return true;
}
return false;
}
+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
@@ -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
@@ -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 -4
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)
@@ -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)
{
@@ -261,6 +261,8 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config)
{
assert(key);
if (!unsafe_yyjson_equals_str(key, "percent"))
return false;
@@ -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)
{
@@ -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>
@@ -222,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__)
@@ -270,13 +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);
}
else
{
if (exePath->length == 0)
ffStrbufSetS(exePath, filePath);
}
}
#elif defined(__APPLE__)
@@ -318,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);
}
}
}
@@ -403,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,10 +1,12 @@
#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 <stdalign.h>
#include <windows.h>
#include <ntstatus.h>
#include <winternl.h>
enum { FF_PIPE_BUFSIZ = 8192 };
@@ -51,7 +53,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
wchar_t pipeName[32];
static unsigned pidCounter = 0;
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", GetCurrentProcessId(), ++pidCounter);
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", instance.state.platform.pid, ++pidCounter);
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = CreateNamedPipeW(
pipeName,
@@ -152,7 +154,7 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
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
@@ -172,7 +174,7 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
CancelIo(hChildPipeRead);
TerminateProcess(hProcess, 1);
return "GetOverlappedResult"
#if __aarch64__
#if !FF_WIN7_COMPAT
"Ex"
#endif
"(hChildPipeRead) failed";
@@ -193,9 +195,16 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
exit:
{
DWORD exitCode = 0;
if (GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE && exitCode != 0)
return "Child process exited with an error";
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;
@@ -204,15 +213,12 @@ exit:
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)
return false;
if (gui)
*gui = GetGuiResources(hProcess, GR_GDIOBJECTS) > 0;
if(ppid)
{
PROCESS_BASIC_INFORMATION info = {};
@@ -225,23 +231,41 @@ bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFst
else
return false;
}
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(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* imagePath = (UNICODE_STRING*)buffer;
ffStrbufSetNWS(exe, imagePath->Length / sizeof(wchar_t), imagePath->Buffer);
if (exePath) ffStrbufSet(exePath, exe);
if (pname && exeName)
{
*exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1;
ffStrbufSetS(pname, *exeName);
}
}
else
return false;
}
if(pname && exeName)
if (gui)
{
*exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1;
ffStrbufSetS(pname, *exeName);
SECTION_IMAGE_INFORMATION info = {};
ULONG size;
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageInformation, &info, sizeof(info), &size)))
{
assert(size == sizeof(info));
*gui = info.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI;
}
else
return false;
}
return true;
@@ -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>
@@ -201,7 +201,7 @@ FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaNa
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
{
FFDBusData dbus;
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
return FF_VARIANT_NULL;
@@ -260,7 +260,7 @@ FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName,
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
{
FFDBusData dbus;
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
return FF_VARIANT_NULL;
+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)
{
@@ -109,7 +109,7 @@ typedef struct FFSmbios20EntryPoint
uint8_t SmbiosBcdRevision;
} __attribute__((__packed__)) FFSmbios20EntryPoint;
static_assert(offsetof(FFSmbios20EntryPoint, SmbiosBcdRevision) == 0x1E,
"FFSmbios30EntryPoint: Wrong struct alignment");
"FFSmbios20EntryPoint: Wrong struct alignment");
typedef struct FFSmbios30EntryPoint
{
@@ -434,7 +434,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
return &table;
}
#elif defined(_WIN32)
#include <windows.h>
#include "common/windows/nt.h"
#pragma GCC diagnostic ignored "-Wmultichar"
@@ -450,36 +450,52 @@ typedef struct FFRawSmbiosData
const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable()
{
static FFRawSmbiosData* buffer;
static SYSTEM_FIRMWARE_TABLE_INFORMATION* buffer;
static FFSmbiosHeaderTable table;
if (!buffer)
{
FF_DEBUG("Initializing Windows SMBIOS buffer");
const DWORD signature = 'RSMB';
FF_DEBUG("Querying system firmware table size with signature 'RSMB'");
uint32_t bufSize = GetSystemFirmwareTable(signature, 0, NULL, 0);
if (bufSize <= sizeof(FFRawSmbiosData)) {
FF_DEBUG("Invalid firmware table size: %u (must be > %zu)",
bufSize, sizeof(FFRawSmbiosData));
SYSTEM_FIRMWARE_TABLE_INFORMATION sfti = {
.ProviderSignature = 'RSMB',
.Action = SystemFirmwareTableGet,
};
ULONG bufSize = 0;
NtQuerySystemInformation(SystemFirmwareTableInformation, &sfti, sizeof(sfti), &bufSize);
if (bufSize <= sizeof(FFRawSmbiosData) + sizeof(sfti)) {
FF_DEBUG("Invalid firmware table size: %lu (must be > %zu)", bufSize, sizeof(FFRawSmbiosData) + sizeof(sfti));
return NULL;
}
FF_DEBUG("Firmware table size: %u bytes", bufSize);
if (bufSize != sfti.TableBufferLength + (ULONG) sizeof(sfti)) {
FF_DEBUG("Firmware table size mismatch: NtQuerySystemInformation returned %lu but expected %lu",
bufSize, sfti.TableBufferLength + (ULONG) sizeof(sfti));
return NULL;
}
FF_DEBUG("Firmware table size: %lu bytes", bufSize);
buffer = (FFRawSmbiosData*) malloc(bufSize);
assert(buffer);
buffer = malloc(bufSize);
*buffer = sfti;
FF_DEBUG("Allocated buffer for SMBIOS data");
FF_MAYBE_UNUSED uint32_t resultSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize);
assert(resultSize == bufSize);
if (!NT_SUCCESS(NtQuerySystemInformation(SystemFirmwareTableInformation, buffer, bufSize, &bufSize)))
{
FF_DEBUG("NtQuerySystemInformation(SystemFirmwareTableInformation) failed");
free(buffer);
buffer = NULL;
return NULL;
}
FFRawSmbiosData* rawData = (FFRawSmbiosData*) buffer->TableBuffer;
FF_DEBUG("Successfully retrieved SMBIOS data: version %u.%u, length %u bytes",
buffer->SMBIOSMajorVersion, buffer->SMBIOSMinorVersion, buffer->Length);
rawData->SMBIOSMajorVersion, rawData->SMBIOSMinorVersion, rawData->Length);
FF_DEBUG("Parsing SMBIOS table structures");
FF_MAYBE_UNUSED int structureCount = 0;
for (
const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer->SMBIOSTableData;
(const uint8_t*) header < buffer->SMBIOSTableData + buffer->Length;
const FFSmbiosHeader* header = (const FFSmbiosHeader*) rawData->SMBIOSTableData;
(const uint8_t*) header < rawData->SMBIOSTableData + rawData->Length;
header = ffSmbiosNextEntry(header)
)
{
@@ -1,4 +1,4 @@
#include "sysctl.h"
#include "common/sysctl.h"
#include <stdlib.h>

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