Compare commits

...

659 Commits

Author SHA1 Message Date
李通洲 eff8514536 CI (macOS): builds Intel version with macport 2026-09-12 00:08:16 +08:00
李通洲 f37a5a2543 OpenBSD: removes kvm dep 2026-09-11 23:38:10 +08:00
Carter Li 9a9f82b59e Processes (macOS): adds a comment 2026-09-11 10:40:44 +08:00
Carter Li 29818d2dca Top (macOS): improves performance and accuracy‌ of process name 2026-09-11 10:36:16 +08:00
Carter Li 222fe7e3f9 3rdparty (yyjson): upgrades to 0.13.0 2026-09-09 13:49:56 +08:00
Stian Halseth 7d0256fb85 CPU (Linux): adds SPARC support (#2572)
/proc/cpuinfo on sparc has none of the fields the generic fallback looks
for, so the module printed "Unknown (64)". The name is in "cpu", and the
frequency in "Cpu<n>ClkTck" -- in Hz, hex on sparc64, decimal on sparc32.
2026-09-08 20:31:55 +08:00
Carter Li a70c37fdaf Logo (Builtin): removes Zerene
Distro discontinued #2567
2026-09-07 10:58:46 +08:00
Sultaniiazov David 66e9e38f28 Logo (Builtin): adds ALT Atomic (#2549)
Co-authored-by: Vladimir Romanov <rirusha@altlinux.org>
2026-09-06 23:29:42 +08:00
李通洲 5d290cc3d5 Common (CommandOption): find module configuration from JSON config file 2026-09-05 20:14:58 +08:00
Guiorgy 2e542bea64 CMake: bumps min version to 3.21 (#2565)
C_STANDARD C17 and C23 were only introduced in CMake 3.21
2026-09-05 13:43:05 +08:00
李通洲 c708b6f5cd CPU (Linux): adds apple code of M5x 2026-09-05 00:32:58 +08:00
李通洲 6a275da8b1 Sound: removes an unused file 2026-09-05 00:32:31 +08:00
李通洲 ecee5694fb Global: uses strtoull for uint64_t
Fixes #2563 #2564
2026-09-04 19:35:26 +08:00
Matt Housh 4e78f1b703 Packages (Linux): adds support for package detection for CRUX linux 2026-09-04 18:14:21 +08:00
李通洲 62f78ca60c Processes (Windows): uses SystemHandleCountInformation if available 2026-09-03 15:27:40 +08:00
李通洲 00af2d1df2 WM: uses SystemBasicProcessInformation if available 2026-09-03 10:04:55 +08:00
李通洲 1128a75d8c InitSystem: uses SystemBasicProcessInformation if available 2026-09-03 10:04:55 +08:00
Carter Li ce61783c4b Wallpaper (macOS): extracts image path from NSData Configuration field
Also moves NSWorkspace method to the last method to try

Fixes #2559
2026-09-03 09:57:08 +08:00
Piotr Kubaj 20597bff00 Logo (image): also try unsuffixed ImageMagick library names
FreeBSD (and other systems that build ImageMagick without encoding the
quantum depth into the library name) install libMagickCore-7.so and
libMagickCore-6.so without a .Q16HDRI / .Q16 suffix.  dlopen currently
only tries the suffixed names, so image logos always fall back to ASCII
art with "Image Magick library not found" even when ImageMagick is
installed.  Append the plain library names as a last resort.
2026-09-02 17:06:16 +08:00
Carter Li caf64f5e4d Packaging: updates debian stuff [ci skip] 2026-09-02 10:52:57 +08:00
Carter Li 90a6e90b19 Processes (macOS): eliminates a compiler warning 2026-09-02 10:45:52 +08:00
Carter Li e9f719f37a Doc: update CONTRIBUTING.md [ci skip] 2026-09-02 10:44:47 +08:00
Carter Li 8c98bf1953 CMake: discovers module file automatically 2026-09-02 10:44:47 +08:00
Carter Li 1c1136ebd1 Merge pull request #2555 from fastfetch-cli/dev
Release: v2.68.1
2026-09-01 19:44:59 +08:00
李通洲 2787d97973 Release: v2.68.1 2026-09-01 19:21:56 +08:00
李通洲 2e06a73102 Modules: exposes localized module name in custom key format as {module-name} 2026-09-01 19:18:02 +08:00
Carter Li 37c198d997 Revert "CMAKE: bumps minimum CMake version to 3.21.0 (#2517)" (#2554)
I don't know why bumping minimal CMake version changes the behavior of cpack, but it does.

Fixes #2553

This reverts commit 233c481f7a.
2026-09-01 18:58:08 +08:00
Carter Li 37afe5a79d Packaging: updates debian stuff [ci skip] 2026-09-01 16:35:30 +08:00
Carter Li 0ebf09754b Merge pull request #2551 from fastfetch-cli/dev
Release: v2.68.0
2026-09-01 16:20:15 +08:00
Carter Li 0b1bc5b527 CI: upgrades deps; reenables Haiku 2026-09-01 14:14:14 +08:00
Carter Li 3d107764fa Wifi (Linux): fixes compatibility with old kernel headers 2026-09-01 14:14:14 +08:00
李通洲 4863a173e4 Wifi (linux): enables netlink on big-endian platforms 2026-09-01 00:34:55 +08:00
李通洲 8ea4468eec Common (Endian): adds new header 2026-09-01 00:20:40 +08:00
李通洲 b0ba084b5e Global: address review comments v2 2026-08-31 22:03:06 +08:00
李通洲 43d01f26ea Top: handle unknown process names gracefully in output 2026-08-31 20:38:20 +08:00
李通洲 b5ffc32b80 Top / Processes (Windows): improves detection of system / kernel processes detection 2026-08-31 20:37:31 +08:00
李通洲 4ff931c06f Top: adds thread count detection 2026-08-31 20:37:31 +08:00
李通洲 6eef800ea2 Top: supports sorting by start-time 2026-08-31 19:47:14 +08:00
李通洲 b9e4d04d65 Global: addresses review comments generated by CI 2026-08-31 19:10:27 +08:00
Carter Li 9c791b2c12 Doc: adds CONTRIBUTING.md 2026-08-31 15:31:45 +08:00
Carter Li 76b6768141 JsonSchema: regenerates moduleFormat 2026-08-31 15:31:45 +08:00
Carter Li 42002a6240 CPU (Linux): supports more Snapdragon X SoCs 2026-08-31 15:31:45 +08:00
Carter Li ef7f5aeac3 CPU (Android): adds pretty names of new SoCs 2026-08-31 14:26:16 +08:00
Carter Li d5214af189 Global: fixes British spellings and typos found by AI 2026-08-31 13:44:19 +08:00
Carter Li a33d6326f1 CMake: enables CONFIGURE_DEPENDS to FF_MODULE_DIRS globbing 2026-08-31 13:31:21 +08:00
Carter Li df99241424 L10n (gl): adds missing missing Galician translations 2026-08-31 13:11:00 +08:00
dependabot[bot] 5b1ad1008d CI: Bump the github-actions group with 3 updates
Bumps the github-actions group with 3 updates: [uraimo/run-on-arch-action](https://github.com/uraimo/run-on-arch-action), [github/codeql-action/init](https://github.com/github/codeql-action) and [github/codeql-action/analyze](https://github.com/github/codeql-action).


Updates `uraimo/run-on-arch-action` from 3.1.0 to 3.2.0
- [Release notes](https://github.com/uraimo/run-on-arch-action/releases)
- [Commits](https://github.com/uraimo/run-on-arch-action/compare/f9b26e3a1a408d5fd530d20c17b9f3f4428ff8d9...460cb8e6d9f726a588fc9b5e681c8a6cab09ae41)

Updates `github/codeql-action/init` from 4.37.7 to 4.37.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28)

Updates `github/codeql-action/analyze` from 4.37.7 to 4.37.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd...db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28)

---
updated-dependencies:
- dependency-name: uraimo/run-on-arch-action
  dependency-version: 3.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-31 08:41:25 +08:00
李通洲 39024abae9 Processes (Haiku): honors options->countKprocs 2026-08-30 19:54:58 +08:00
Carter Li 4dba32aabb WM (macOS): improves reliability of WM plugin detection 2026-08-30 19:04:09 +08:00
李通洲 753ddec3c5 Memory (Windows): prefers NQSI 2026-08-29 20:09:48 +08:00
Carter Li b04587e0cb Presets: moves top to the bottom of running modules [ci skip] 2026-08-29 13:03:49 +08:00
Carter Li 3abcf4195f Processes: corrects the structure of JSON result 2026-08-29 12:14:09 +08:00
李通洲 af8a42270c Top (Hurd): reports startTime; uses time_value64_t 2026-08-29 12:09:40 +08:00
李通洲 1c9e521775 Top: disables FF_TOP_TYPE_DISK on Hurd and Haiku 2026-08-29 12:09:31 +08:00
Carter Li 7fe08bddd0 Processes: adds option countKprocs 2026-08-29 00:58:15 +08:00
Carter Li 41da49f579 Top (SunOS / Hurd): skips kernel tasks 2026-08-29 00:40:08 +08:00
Carter Li f169165599 Top (Linux): improves performance of stat parsing 2026-08-28 18:45:30 +08:00
Carter Li 2c4caf8e0d Top: removes realloc retries 2026-08-28 16:22:33 +08:00
Carter Li 51b370a105 Processes: adds total thread count detection 2026-08-28 15:46:23 +08:00
Carter Li 14cf6bfdc1 Top (macOS): adds comments 2026-08-28 15:46:23 +08:00
Carter Li 4d00dc6802 Logo (Builtin): adds omarchy 2026-08-28 09:49:48 +08:00
Carter Li d7de7c41ca CI: disables fail on alert 2026-08-27 15:28:18 +08:00
Carter Li d80fe3f004 Logo (Builtin): adds macOS_old 2026-08-27 14:58:32 +08:00
Carter Li dcce4ccdb0 CI: moves benchmark-index to /.github as required by the script 2026-08-27 14:57:22 +08:00
Carter Li 191c5f2ef5 Doc: updates README 2026-08-27 14:29:17 +08:00
Carter Li 1dc794fac0 Doc: updates changelog [ci skip] 2026-08-27 14:23:16 +08:00
Carter Li 5936c1cef4 CI: adds benchmark job 2026-08-27 14:23:16 +08:00
Carter Li 04f26a29eb CI: enables bluetooth module on platforms other than macOS 2026-08-27 09:45:58 +08:00
Carter Li c9ad429a1b Global: introduces global macro FF_PATH_PKG_BASE to replace _PATH_LOCALBASE 2026-08-26 23:12:25 +08:00
李通洲 2b42db58da LM (OpenBSD): adds support 2026-08-26 17:43:25 +08:00
Carter Li 32757b0e43 LM (Windows): adds support 2026-08-26 17:43:25 +08:00
Carter Li c5598d2361 LM (macOS): adds support 2026-08-26 17:43:25 +08:00
Carter Li 203cd7cbcf LM (Linux): adds pretty name 2026-08-26 17:43:25 +08:00
Carter Li fb309134b5 LM (Linux): queries systemd session info via dbus 2026-08-26 17:43:25 +08:00
Carter Li 8b162e89de WMDE: improves performance 2026-08-26 14:14:24 +08:00
Carter Li 9670b585fb LM: detects LM from processes list if systemd is not available
2. removes type field
3. small optimizations
2026-08-26 14:12:08 +08:00
Carter Li 3b76ade662 Shell: fixes the fast path of ash version detection 2026-08-26 08:50:08 +08:00
李通洲 1b1df2e731 Common (Settings): tidy 2026-08-25 23:27:36 +08:00
李通洲 6c19a8b4ec Top (DragonFly): fixes building 2026-08-25 23:27:24 +08:00
李通洲 71728247ab Common (Sysctl): handle varying data lengths in integer retrieval functions 2026-08-25 23:24:31 +08:00
李通洲 4344aa2ff1 Top: adds option showType: <cpu|mem|disk> 2026-08-25 20:48:34 +08:00
李通洲 b7d8c12015 CI: adds top module 2026-08-25 18:24:32 +08:00
Carter Li 63d16ca854 Top: removes option kernelTask (never implemented) 2026-08-25 16:30:04 +08:00
Carter Li f15a1e96ce Top (Linux): don't error out when reading /proc/pid/io fails 2026-08-25 16:27:53 +08:00
Carter Li 55bfcd6d86 Top (Android): fixes building 2026-08-25 13:35:32 +08:00
Carter Li 880284fa9c DisplayServer (Android): enables Wayland support
Fixes #2530
2026-08-25 13:32:28 +08:00
Carter Li 143939f19b DE (Android): adds asus zenfone support
Fixes #2541
2026-08-25 09:08:35 +08:00
dependabot[bot] a979d8ae81 CI: Bump the github-actions group with 4 updates
Bumps the github-actions group with 4 updates: [cross-platform-actions/action](https://github.com/cross-platform-actions/action), [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [signpath/github-action-submit-signing-request](https://github.com/signpath/github-action-submit-signing-request).


Updates `cross-platform-actions/action` from 1.3.0 to 1.4.0
- [Release notes](https://github.com/cross-platform-actions/action/releases)
- [Changelog](https://github.com/cross-platform-actions/action/blob/master/changelog.md)
- [Commits](https://github.com/cross-platform-actions/action/compare/5ea7e8e4677bd726033a10b094ba1c5762b15dee...24ef01df165c76df1ed2b9f9e9212e78dc2fc963)

Updates `github/codeql-action/init` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

Updates `github/codeql-action/analyze` from 4.37.6 to 4.37.7
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5595ccaf912efad79be6eef63a5619ff05969be3...ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd)

Updates `signpath/github-action-submit-signing-request` from 2.2 to 2.3
- [Release notes](https://github.com/signpath/github-action-submit-signing-request/releases)
- [Commits](https://github.com/signpath/github-action-submit-signing-request/compare/b9d91eadd323de506c0c81cf0c7fe7438f3360fd...c92b958760219087e01f8d67a1669ed57afe2627)

---
updated-dependencies:
- dependency-name: cross-platform-actions/action
  dependency-version: 1.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: signpath/github-action-submit-signing-request
  dependency-version: '2.3'
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-24 11:31:38 -05:00
Carter Li b5897f784f Processes (GNU): uses native impl 2026-08-25 00:05:49 +08:00
Carter Li 83cc7a94a4 Top: adds new module 2026-08-25 00:05:49 +08:00
李通洲 5edda068f2 PhysicalDisk (DragonFly): eliminates‌ compiler warnings 2026-08-24 20:58:50 +08:00
Carter Li 6d5cb520ed Logo (Builtin): adds artix2 in 2026-08-24 13:21:25 +08:00
Carter Li e7ecba4460 Doc: updates README [ci skip] 2026-08-21 10:40:50 +08:00
Carter Li e0c239729b L10n: adds cs id tr uk vi
Assisted-By: LLM
2026-08-21 10:19:06 +08:00
Samuel Torres 6570a7accc L10n (ES): fixes Spanish translations (#2537) 2026-08-21 08:31:42 +08:00
Samuel Torres 0c4ec62cac L10n: (gl) Added Galician Support 2026-08-21 00:25:32 +08:00
Carter Li 5d11b65d53 TerminalFont (Android): adds font size detection 2026-08-20 16:18:07 +08:00
Carter Li 8b40117c08 Wifi (OpenBSD): fortifies detection and adds channel to frequency helper 2026-08-20 16:04:00 +08:00
Carter Li b1f2bf3526 WM: uses full name in EN, as DE and LM modules do 2026-08-20 15:23:21 +08:00
Carter Li d8452f71ed Wifi (SunOS): fortifies code 2026-08-20 15:05:18 +08:00
Carter Li 2a269bfd4c Wifi: removes driver detection support 2026-08-19 23:28:23 +08:00
Carter Li cafe82b462 Battery (SunOS): adds basic detection impl 2026-08-19 13:24:05 +08:00
Carter Li db8ee8159d Wifi (Haiku): adds basic Wifi detection impl 2026-08-19 11:05:35 +08:00
Carter Li f0765b1a13 Wifi (SunOS): adds basic Wifi detection impl 2026-08-19 10:43:34 +08:00
Carter Li 93566cb73c Wifi (Android / OpenBSD): inits unsupported properties 2026-08-19 10:16:30 +08:00
Carter Li 6d0d093d62 Wifi (NetBSD): adds channel width detection 2026-08-19 10:15:30 +08:00
Carter Li 54fe4ffece Wifi (FreeBSD): adds channel width detection 2026-08-19 09:40:23 +08:00
Carter Li 124bbb06f9 Wifi (macOS): fixes compatibility for old Intel MBP 2026-08-19 09:17:12 +08:00
Carter Li f04a53337d Wifi (macOS): adds channel width, accurate channel frequency and device driver detection 2026-08-18 19:32:01 +08:00
李通洲 514efab8eb Wifi (Windows): adds channel width and device driver detection 2026-08-18 19:32:01 +08:00
Carter Li 232cd6659b Wifi (Linux): adds channel width and device driver detection 2026-08-18 19:32:01 +08:00
Carter Li 7c93f9c82a GPU (macOS): removes useless @available tests 2026-08-18 19:32:01 +08:00
Wehrwolfmann e5b6e3612a L10n: falls back to English when the auto-detected locale is unsupported
--key-language with an empty value (and "language": null in the config)
asks for the system locale, not for a specific language. When that locale
has no translation, fastfetch aborted with exit 477 instead of printing
anything, so the same config broke on every locale outside the twelve
supported ones, and under LC_ALL=C variants such as POSIX.

Auto-detected locales now fall back to English. An explicitly requested
language still errors out, so typos and zh are still reported.
2026-08-17 20:14:39 -05:00
Carter Li 6cb15885c7 L10n: don't use ffStrbufCreateStatic for buffers that will be modified later 2026-08-18 09:11:50 +08:00
Carter Li e6d90c2081 L10n (Zh): uses a different name for Monitor 2026-08-17 14:20:46 +08:00
Carter Li 679d868b4a L10n (Zh): clarifies Disk actually detects Disk partitions 2026-08-17 13:57:23 +08:00
Carter Li 72d240f325 L10n (Zh): clarifies Bluetooth actually detects Bluetooth devices 2026-08-17 13:42:30 +08:00
Carter Li 2ca7e037ef L10n (Zh): translates shell 2026-08-17 13:36:09 +08:00
Carter Li 5e9c31ac31 Completion (Fish): prints enum description [ci skip] 2026-08-17 10:42:24 +08:00
Wehrwolfmann bcb48774a0 Modules: proofreads Russian l10n strings 2026-08-16 12:01:42 -05:00
Wehrwolfmann 9ff7969acf Bluetooth / BluetoothRadio: keeps the brand name in Latin script in Russian keys 2026-08-16 12:01:42 -05:00
李通洲 7fbd06a135 Doc: updates README.md [ci skip] 2026-08-16 22:16:56 +08:00
Hashing bbb906ba10 L10n (Pt): matches all Portuguese locales, not only bare pt (#2521)
359cb0a79a renamed the key from `pt_BR` to
`pt` but kept the exact-match guard, so only the literal string `pt`
matched. Every real Portuguese locale (`pt_BR`, `pt_PT` and their charset
and modifier variants) fell through to `goto error` and aborted.

Return the offset unconditionally, matching every other two-letter case.
2026-08-16 02:15:39 -05:00
李通洲 2de674ec9a L10n (Ar / He): adds support
Fixes #2520
2026-08-16 10:52:23 +08:00
李通洲 b700d9ded5 L10n (Ru): changes Блютус to Блютуз
Ref: https://github.com/fastfetch-cli/fastfetch/issues/2503#issuecomment-5304614812
2026-08-16 10:52:23 +08:00
李通洲 359cb0a79a L10n (Pt): renames pt_BR to pt 2026-08-16 10:52:14 +08:00
李通洲 45f9de6cd2 L10n: improves performance 2026-08-16 10:36:33 +08:00
Guiorgy 233c481f7a CMAKE: bumps minimum CMake version to 3.21.0 (#2517)
C_STANDARD 23 was added in 3.21
2026-08-15 09:15:03 +08:00
Carter Li b677f1e902 Theme: improves GTK theme/icons/font detection on standalone WMs (Hyprland, sway, niri, i3)
Fixes #2504
2026-08-15 09:08:29 +08:00
Carter Li 8d82eedaef DiskIO / NetIO: updates default value of waitTime to reduce latency
Also corrects docs.
2026-08-15 08:53:00 +08:00
Carter Li 4dc27b365f DiskIO / NetIO: fixes I/O rate calculation precision, prevent div-by-zero 2026-08-15 08:51:45 +08:00
李通洲 e5c3fa4023 CI: fixes compiling errors 2026-08-15 00:00:27 +08:00
李通洲 bdba78c45c CI: silences codespell errors 2026-08-14 23:56:29 +08:00
Carter Li f95167e907 Global: adds option key-language
Fixes #2503
2026-08-14 23:33:54 +08:00
Carter Li 3908c39ce2 Modules: adds l10n strings 2026-08-14 22:47:24 +08:00
李通洲 858d3749f4 FFstrbuf: adds FF_STRBUF_STATIC 2026-08-14 18:27:53 +08:00
李通洲 51f36fa4b4 FFstrbuf: adds comments [ci skip] 2026-08-14 17:54:36 +08:00
李通洲 bfe30eec79 Doc: updates changelog [ci skip] 2026-08-14 17:05:06 +08:00
Carter Li 4dd2f2d34b Merge pull request #2516 from fastfetch-cli/dev 2026-08-14 01:20:28 -05:00
Carter Li 60431c0321 Doc: update changelog [ci skip] 2026-08-14 13:50:22 +08:00
李通洲 7b2b3405ae Locale (Windows): reports the code page used by the console 2026-08-14 13:38:14 +08:00
Carter Li 965ed4ba79 Library (Windows): don't assume DataTableEntry->FullDllName is null-terminated 2026-08-14 09:41:30 +08:00
李通洲 00603357ea Processing (Windows): improves performance of environement string creation 2026-08-14 09:41:30 +08:00
OctoBored 5ea299a8d2 Doc: restores Star History in README.md
The Star History chart was removed in 8df0a1c9 (Fixes #2508) because the previous chart was broken due to GitHub stargazer API restrictions. This restores it at the same location using a working data source that requires no API token, so the chart renders correctly again.
2026-08-13 05:43:43 -05:00
Carter Li 368a4c5a73 Release v2.67.1 2026-08-13 11:02:18 +08:00
Carter Li 8df0a1c97e Doc: removes Star History in README.md
Fixes #2508
2026-08-13 10:44:35 +08:00
Carter Li 7098cd86cb Display: fixes bright colours incorrectly active in light theme
Fixes #2509
2026-08-13 10:44:35 +08:00
njk 681749ed54 TerminalFont (Ghostty): fixes font-family fallback order (#2510) 2026-08-12 20:04:19 -05:00
李通洲 c4695b8cf1 Processing (Windows): sets LANG=C when spawning child processes 2026-08-12 13:54:32 +08:00
李通洲 1d12003555 Locale (Windows): uses $LANG if available e.g. MSYS2 2026-08-12 10:19:22 +08:00
Carter Li 16b10c162b Revert "Locale (macOS): queries system-wide locale preference"
This reverts commit 8b8efcdcce.
2026-08-12 10:07:34 +08:00
Carter Li 51cfd4b5ed OS (Android): optimises code 2026-08-12 09:52:31 +08:00
JunaidQrysh a0452b8323 Logo (Image): don't block images support in zellij 2026-08-11 17:41:45 +08:00
Carter Li ebf38e829d OS (Android): reports real code names 2026-08-11 11:02:20 +08:00
HashimAbdulaziz 4c2af4071c TerminalFont (Alacritty): fix font size never being parsed from config
The query array gained a third entry in
dd30c82b83 but numQueries stayed at 2, so
`size =` was never queried and every Alacritty user silently got the
hardcoded 11.25 fallback.
2026-08-09 02:23:17 -05:00
李通洲 e3b8e94055 Wallpaper (macOS): uses the official API if possible 2026-08-09 11:33:58 +08:00
李通洲 1d4b0236ac WMTheme (macOS): migrates impl to pure C using CoreFoundation 2026-08-09 10:25:13 +08:00
李通洲 da42108732 Cursor (macOS): migrates impl to pure C using CoreFoundation 2026-08-09 10:22:21 +08:00
李通洲 8b8efcdcce Locale (macOS): queries system-wide locale preference 2026-08-09 10:12:37 +08:00
李通洲 8bc4464b64 Library: makes ffLibraryIterateDynamicLibs return false on failure 2026-08-09 10:11:25 +08:00
Carter Li 4361c5e787 Library: adds function ffLibraryIterateDynamicLibs 2026-08-09 01:07:19 +08:00
李通洲 558a90d4e0 Loadavg (Haiku): adds support on R1B6 2026-08-09 01:07:19 +08:00
Carter Li 881730d0bd TerminalFont: improves Ghostty config loading with fallback support
Fixes: #2500
2026-08-08 22:40:34 +08:00
Carter Li ac8fc63c28 Doc: updates changelog [ci skip] 2026-08-07 16:39:23 +08:00
Yelninei 8686820c1a CMake (Hurd): Define O_PATH to O_NORW.
This is a noop because O_RW is 0 but O_NORW is the correct constant to
open a file without read/write permissions.
2026-08-07 02:23:29 -05:00
Carter Li 39b3dc001a CMake: adds C23 feature detection and compatibility workarounds for Apple clang 17 2026-08-07 11:00:12 +08:00
Carter Li ba60d7975c Camera (macOS): simplifies code 2026-08-07 09:37:39 +08:00
Carter Li 51a4f34bb5 Codec (macOS): fixes a symbol not found error when running on 10.15 2026-08-07 09:37:39 +08:00
Carter Li 01bb73b9e8 Packaging: updates debian stuff [ci skip] 2026-08-06 16:40:38 +08:00
Carter Li 56da8f8110 Merge pull request #2497 from fastfetch-cli/dev 2026-08-06 03:07:26 -05:00
dependabot[bot] 6d6302e327 CI: Bump the github-actions group with 2 updates
Bumps the github-actions group with 2 updates: [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) and [signpath/github-action-submit-signing-request](https://github.com/signpath/github-action-submit-signing-request).


Updates `docker/setup-qemu-action` from 4.1.0 to 4.2.0
- [Release notes](https://github.com/docker/setup-qemu-action/releases)
- [Commits](https://github.com/docker/setup-qemu-action/compare/06116385d9baf250c9f4dcb4858b16962ea869c3...96fe6ef7f33517b61c61be40b68a1882f3264fb8)

Updates `signpath/github-action-submit-signing-request` from 1.3 to 2.2
- [Release notes](https://github.com/signpath/github-action-submit-signing-request/releases)
- [Commits](https://github.com/signpath/github-action-submit-signing-request/compare/ced31329c0317e779dad2eec2a7c3bb46ea1343e...b9d91eadd323de506c0c81cf0c7fe7438f3360fd)

---
updated-dependencies:
- dependency-name: docker/setup-qemu-action
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: signpath/github-action-submit-signing-request
  dependency-version: '2.2'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-05 21:28:37 -05:00
Carter Li 20277b9ee9 CI: adds dependabot.yml 2026-08-06 10:17:14 +08:00
Thibaud-Vdb b6d95a0ce5 CI: declares least-privilege token permissions
Jobs without a permissions block get the repository's default token
scope, and reusable workflow calls pass the caller's grants straight
through. Scopes are now derived from what each workflow actually does
with the token:

- every build workflow declares contents: read; none of them writes
  through the GITHUB_TOKEN.
- build-linux-hosts.yml keeps security-events: write for the CodeQL
  upload; the other callers had that grant too but never upload
  scanning results, so they drop it.
- build-windows-hosts.yml gets actions: read, which the SignPath
  action documents needing to read job details and download the
  unsigned artifact.
- build-release.yml declares contents: write, matching the grant its
  caller already makes for creating the release.

Runs that execute pull request code now hold a token that can do
nothing but read the repository.
2026-08-05 20:59:02 -05:00
Thibaud-Vdb daf5421be7 CI: passes only the secret each reusable workflow needs
Every reusable workflow call used 'secrets: inherit', which hands the
caller's whole secret set to the called workflow, but the only secret
any of them reads is SIGNPATH_API_TOKEN in build-windows-hosts.yml.
Passing that one secret explicitly and dropping inherit everywhere else
means a compromised step in, say, a BSD build VM has no signing token
to steal, and the workflow files now show exactly which secret flows
where.

The secret is declared optional in the reusable workflow so runs
without it (pull requests, forks) behave as before; the signing step
is already guarded to upstream push events.
2026-08-05 20:59:02 -05:00
Thibaud-Vdb b739dfee0b CI: pins actions to commit SHAs
A version tag like @v1 or a branch like @master is a movable pointer:
whoever controls the action repository can re-point it, and the next
run executes whatever it points at. Several of these actions run in
jobs whose outputs ship to users: build-release.yml creates the GitHub
release with the downloadable binaries, and build-windows-hosts.yml
holds the SignPath signing token, so a re-pointed tag there could ship
a tampered or wrongly signed release. This is exactly how the
tj-actions/changed-files compromise propagated (CVE-2025-30066).

Pinning by full commit SHA makes the reviewed code the code that runs,
the same way docker/setup-qemu-action is already pinned in
build-linux-vms.yml. Refs that pointed at master (cross-platform-actions,
setup-alpine, get-latest-release) are pinned to their latest release
tag. Every pin keeps a version comment, and each SHA was resolved from
the upstream repository and cross-checked against its release tag.
2026-08-05 20:59:02 -05:00
Carter Li 80101a5803 GenConfig: simplifes code 2026-08-05 15:47:42 +08:00
Carter Li cf33bef128 CI: fixes building 2026-08-05 15:30:32 +08:00
Carter Li 7e786bee31 GenConfig: optimises code 2026-08-05 15:21:39 +08:00
Carter Li cbea6c3cb1 Presets (neofetch): shows board name as host name
... when the real host name is not available
2026-08-05 15:02:47 +08:00
Carter Li 48a234d742 GenConfig: removes unused fflush 2026-08-05 14:49:29 +08:00
Carter Li c271708f7d GenConfig: don't use Unicode string when drawing options 2026-08-05 14:36:42 +08:00
Carter Li b42f11442c GenConfig: improves visibility on light-background terminal 2026-08-05 14:28:49 +08:00
Carter Li 73918956d7 GenConfig: prefers macros instead of hard coded ANSI string 2026-08-05 14:28:49 +08:00
Carter Li 6559c7f42d GenConfig: don't use Unicode chars on niche platforms 2026-08-05 14:28:11 +08:00
Carter Li 56950e790f Merge pull request #2490 from fastfetch-cli/dev
Release v2.67.0
2026-08-04 20:05:50 -05:00
Carter Li e7642ea3a2 GenConfig: honors -s set by users 2026-08-04 23:34:15 +08:00
李通洲 a88ef86ce3 InitSystem (Windows): fixes logic of assertions 2026-08-04 21:15:34 +08:00
李通洲 fcf4aca3b7 Shell: fixes a potencial out-of-bound read 2026-08-04 21:14:48 +08:00
李通洲 3f8d141313 GenConfig: disables the feature on Win 8.1; improves redraw logic 2026-08-04 21:05:07 +08:00
李通洲 97a9be27b9 GenConfig: fixes arrow keys not working in Haiku 2026-08-04 20:17:05 +08:00
李通洲 dc46ecbcac GenConfig: code cleanup 2026-08-04 19:34:14 +08:00
李通洲 984fadf70f Revert "Global: first step to full C++ project"
This reverts commit 241ddb79b0.
2026-08-04 19:19:37 +08:00
李通洲 1a42cbe1cf Common (Format): format 2026-08-04 19:18:23 +08:00
Carter Li 9c7cfb864f Release: v2.67.0 2026-08-04 16:28:33 +08:00
Carter Li 6d795a3572 Fastfetch: adds interactive --gen-config mode
removes `--gen-config-*` flags (merged into `--gen-config`)
2026-08-04 15:32:44 +08:00
Carter Li 2af56232a4 FFlist: adds FF_LIST_INSERT_AT and FF_LIST_REMOVE_AT 2026-08-04 15:08:50 +08:00
Carter Li 3196f5efaa chore: adds defaultOrder to every module's definition 2026-08-04 09:58:31 +08:00
aldahiiir 1626ced83c OS (Linux): detects Ubuntu Studio installed with core mode
The minimal (core) installation ships the `ubuntustudio-desktop-core`
metapackage instead of `ubuntustudio-desktop`, so the existing check
missed it and the system was reported as Kubuntu.

Fixes #2485
2026-08-03 20:01:47 +08:00
李通洲 241ddb79b0 Global: first step to full C++ project 2026-08-03 20:00:27 +08:00
李通洲 66ce39e3fc Shell (Windows): fixes incompatibility with the newest fish version 2026-08-02 22:02:54 +08:00
李通洲 3fae9e0274 Libc (Windows): simplifies code 2026-07-31 23:12:10 +08:00
李通洲 5eaf98ecd2 Common: forces optionBuf to be 8-byte aligned 2026-07-29 20:15:54 +08:00
Carter Li 00b7c5b56c Netif (Hurd): fixes a compiler warning 2026-07-28 23:42:08 +08:00
李通洲 305ab14e7b DisplayServer (Linux): don't assume the monitor has only one preferred mode
Fixes #2481
2026-07-28 23:41:07 +08:00
Carter Li a58fc4f77d CI: disable Haiku
Ref: https://github.com/haikuports/haikuports/issues/14445
2026-07-28 15:21:28 +08:00
Carter Li b653ef730d General: removes general.preRun due to security concerns 2026-07-28 15:16:30 +08:00
Carter Li dc464d6efe FFstrbuf: prefers ffStrbufEnsureFree 2026-07-28 14:51:54 +08:00
Carter Li 1c3f0eb7c0 FFstrbuf: adds integer overflow checks to EnsureFreeNoCheck and EnsureFixedLengthFree 2026-07-28 14:51:37 +08:00
Carter Li 476cd67345 Networking: adds Content-Length size limit to prevent excessive memory allocation and potential attacks 2026-07-28 13:29:47 +08:00
Carter Li 2c736697d2 Watch: adds -w/--watch as a seconds-based alias for --dynamic-interval
Closes #2478
2026-07-28 10:52:04 +08:00
Carter Li 738ad59f54 Revert "Weather: replaces aggressive exit(1) with proper error handling (#2474)"
This reverts commit c5a8950ad4.
2026-07-28 10:40:33 +08:00
Carter Li 5476e01407 Revert "PublicIP: replaces exit(1) with proper error status"
This reverts commit 18eef29d0a.
2026-07-28 10:38:53 +08:00
Carter Li 4f0b00116e PublicIP: fixes invalid URL parser 2026-07-28 10:37:36 +08:00
Carter Li 6490e2707f Networking: relaxes accepted response format 2026-07-28 10:31:32 +08:00
tru3 ccf3909372 Separator: fixes memory leakes
- Add missing ffStrbufDestroy(&options->outputColor) in ffDestroySeparatorOptions
  to prevent memory leak when outputColor is set via JSON config
- Replace two exit(1) calls in ffPreparePublicIp with proper error status
  propagation, matching the pattern used in the weather module
2026-07-24 08:50:59 +08:00
tru3 18eef29d0a PublicIP: replaces exit(1) with proper error status
- Add missing ffStrbufDestroy(&options->outputColor) in ffDestroySeparatorOptions
  to prevent memory leak when outputColor is set via JSON config
- Replace two exit(1) calls in ffPreparePublicIp with proper error status
  propagation, matching the pattern used in the weather module
2026-07-24 08:50:59 +08:00
h4sht f6c25667fe Display: adds missing ffStrbufDestroy calls in ffOptionsDestroyDisplay (#2476)
13 FFstrbuf fields were initialized but never destroyed, potentially
leaking memory when configured via JSON or command-line:
- barBorderLeft, barBorderRight
- barBorderLeftElapsed, barBorderRightElapsed
- barColorElapsed, barColorTotal, barColorBorder
- tempColorGreen, tempColorYellow, tempColorRed
- percentColorGreen, percentColorYellow, percentColorRed

Co-authored-by: tru3 <tru3@tru3.com>
2026-07-24 08:43:31 +08:00
h4sht 97fa52fef0 FFstrbuf: removes dead code in ffStrbufSubstrBefore (#2475)
The redundant `if (index < strbuf->length)` check inside the static string
branch is always true since `strbuf->length <= index` is already checked
at the top of the function and returns false. Remove this dead code for clarity.

Co-authored-by: tru3 <tru3@tru3.com>
2026-07-24 08:41:54 +08:00
h4sht c5a8950ad4 Weather: fixes memory leak and replace aggressive exit(1) with proper error handling (#2474)
- Add missing ffStrbufDestroy(&options->location) in ffDestroyWeatherOptions
  to prevent memory leak when location is set via config
- Replace exit(1) in ffPrepareWeather with setting status to an error string,
  allowing the error to be properly propagated through the existing error mechanism

Co-authored-by: tru3 <tru3@tru3.com>
2026-07-24 08:39:07 +08:00
Carter Li 111c1bab75 Codec (macOS): fixes detection for VP9 2026-07-23 09:55:31 +08:00
Carter Li 47dfd8a271 Common (macOS): adds M5x temp detection support 2026-07-22 11:08:17 +08:00
Carter Li bc1d305aaa Logo (Builtin): removes hypros
Ref: #1178 #2460
2026-07-22 09:29:36 +08:00
徐晓伟 dda39f0c67 CI (Linux): adds loong64 build workflow (#2469)
* CI: add loong64 build workflow

Add reusable workflow for building fastfetch on LoongArch 64-bit
architecture using QEMU user-mode emulation + Docker container
(lcr.loongnix.cn/debian:14). Integrate into CI pipeline and
release dependencies.

* CI (loong64): pin docker/setup-qemu-action to full commit SHA

Pin to 06116385d9baf250c9f4dcb4858b16962ea869c3 (v4.1.0) for
immutable action reference as required by Codacy.
2026-07-21 21:14:38 +08:00
李通洲 0b72c9b083 Networking (Windows): simplifies code 2026-07-21 21:12:16 +08:00
李通洲 69f3d9ae33 CI (FreeBSD): fixes building 2026-07-20 16:06:22 +08:00
Carter Li db46e06f2e Common (Base64): unifies the code of endian testing 2026-07-20 15:36:57 +08:00
Carlos Milán Figueredo 7223803a76 Common (Base64): corrects byte order on big-endian hosts (#2470)
ffBase64EncodeRaw unconditionally byte-swapped the input word via
__builtin_bswap32, which only produces the intended big-endian byte
layout on little-endian hosts. On big-endian hosts the word is already
in the correct order, so the swap corrupted the encoded output.

Guard the swap with __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ so the
encoder is correct on both endiannesses.
2026-07-20 02:29:59 -05:00
李通洲 9db4ec82fd Version (macOS): siliences a compiler warning 2026-07-19 18:06:00 +08:00
李通洲 62180366fc Theme (Windows): reports basic is DWM is disabled 2026-07-17 23:00:31 +08:00
Carter Li 0feec933ea Camera: removes unused #includes 2026-07-17 10:40:48 +08:00
Carter Li 6c03db8be9 Codec (macOS): fixes a memory leak 2026-07-17 10:35:30 +08:00
Carter Li f0564fb9a7 Camera: adds missing ffStrbufDestroy 2026-07-17 10:34:56 +08:00
李通洲 8bf1aca7fc GPU (Windows): correctly report virtual GPUs
Fixes #2461
2026-07-16 19:27:39 +08:00
李通洲 445311978e Logo: silence GCC warnings by unsilencing CLANG warnings 2026-07-16 19:14:22 +08:00
Carter Li d9f5e006b5 Logo (Builtin): removes MagpieOS
Dead years ago: https://github.com/magpie-linux
2026-07-16 10:48:12 +08:00
Carter Li 21fbf14fb8 Logo (Builtin): removes Furreto, EmperorOS and Magix
Ref: #2460
2026-07-16 10:46:57 +08:00
Carter Li bc8ce39193 Doc: update logo_request template [ci skip]
Ref: #2460
2026-07-16 10:30:56 +08:00
Carter Li ac3fc219cf Doc: updates README [ci skip] 2026-07-15 09:40:51 +08:00
Carter Li dd30c82b83 TerminalFont: supports both syntax for alacritty 2026-07-15 09:16:03 +08:00
李通洲 b41cdb0ca6 Chore: siliences more compiler warnings 2026-07-14 18:58:00 +08:00
李通洲 2b03bacb28 Global: further code cleanups 2026-07-14 15:07:30 +08:00
李通洲 7dcc7d40d5 InitSystem (Windows): adds support
Note: Windows doesn't have a unix-like init system process, but it does have the first userland process, which is `smss.exe`
2026-07-14 15:04:29 +08:00
Carter Li a0fd59d869 DisplayServer (Linux): don't try to inline functions with variable arguments 2026-07-14 11:05:17 +08:00
Carter Li 1c352bb4de DisplayServer (Linux): removes an old hack 2026-07-14 11:03:00 +08:00
Carter Li 29d626f41d DisplayServer (Linux): wait for delayed Wayland output events
Ref: #2451
2026-07-14 10:56:44 +08:00
Carter Li 8ca6bb084d Common (Library): adds FF_LIBRARY_LOAD_SYMBOL_VAR_LAZY 2026-07-14 10:50:36 +08:00
Carter Li 0b3ef5d35c CMake: adds comments 2026-07-13 10:35:03 +08:00
Carter Li 98c8c5b344 CMake (Linux): detects MUSL automatically 2026-07-13 10:32:12 +08:00
Carter Li eeae601924 Global: silences compiler warnings 2026-07-13 10:03:30 +08:00
Carter Li 773e3ea497 TerminalFont: small code cleanups 2026-07-13 10:03:30 +08:00
clice lee 317c0cfb86 TerminalFont (Ghostty): parse config files statically instead of exec'ing ghostty +show-config (#2122) 2026-07-12 20:59:10 -05:00
李通洲 e0c31be9d5 Battery: changes battery status to array type in custom format 2026-07-11 15:23:24 +08:00
李通洲 75f00af98d Global: replaces __auto_type to auto 2026-07-11 11:23:41 +08:00
李通洲 9d6bb7d717 Global: replaces __typeof__ to typeof 2026-07-11 11:12:23 +08:00
李通洲 2ae9c3da33 CI (Linux): removes armv6li
Doesn't have gcc13+
2026-07-11 08:14:25 +08:00
Carter Li bf1af71d03 Shell (Linux): fixes a potiential fish version detection error 2026-07-11 08:14:25 +08:00
李通洲 61656a1a7a Global: replaces __attribute__ to C23 [[attribute]] 2026-07-11 08:14:21 +08:00
李通洲 ba18705d2e Global: replaces NULL to nullptr 2026-07-10 18:10:09 +08:00
Carter Li 873454191f Global: uses typed enums 2026-07-10 18:09:46 +08:00
Carter Li f8908b9a36 Global: upgrades to C23 2026-07-10 18:09:46 +08:00
Carter Li 8ca551cccc Packaging: updates debian stuff [ci skip] 2026-07-10 15:16:11 +08:00
Carter Li 0869809857 Merge pull request #2446 from fastfetch-cli/dev
Release: v2.66.0
2026-07-10 02:04:09 -05:00
Carter Li c31779e99d CI: ensures CMAKE_BUILD_TYPE is correctly set 2026-07-10 14:44:39 +08:00
Carter Li 89ad35d8a1 GPU (BSD): fixes building when DRM is not enabled 2026-07-10 13:41:13 +08:00
Carter Li d651f3de43 Common (Tracer): updates comments [ci skip] 2026-07-10 13:11:17 +08:00
Carter Li c34c3e5aae Release: v2.66.0 2026-07-10 10:21:45 +08:00
Carter Li c5c61584d9 CPU / GPU (macOS): fixes operator priority bug 2026-07-10 10:12:00 +08:00
Carter Li 48c3b4f980 CPU (Linux): removes ARM core count in CPU name 2026-07-10 08:32:42 +08:00
Carter Li 93bca8d480 CPU (Linux): disables printing package count by default
The detection code is problematic. Let's hide the package count before we can find the root cause.
2026-07-10 08:32:42 +08:00
Carter Li c690fe5aa9 BluetoothRadio: fixes memleaks 2026-07-10 08:32:42 +08:00
Carter Li 55e674e1cb GPU: code cleanups and bug fixes 2026-07-09 20:40:49 +08:00
Carter Li 0495c47909 GPU (Linux): fixes GPU core counting on Asahi Linux 2026-07-09 20:04:11 +08:00
Marvin Hinz 2f79c39f62 OS (Linux): adds support for proxmox backup server detection (#2443)
* add support for proxmox backup server detection

* Update Proxmox identifiers and pretty names

* Simplify Proxmox logo names in p.inc

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-07-09 19:05:22 +08:00
Carter Li 44056f1c85 GPU (Linux): fixes accurate AMD GPU names are not queried in driverSpecific mode 2026-07-08 18:14:06 +08:00
李通洲 6358bd7844 FFstrbuf: optimises ffStrbufEnsureFreeNoCheck 2026-07-07 19:15:36 +08:00
Carter Li 11d77e0d09 Logo (Builtin): updates linuxmint_small 2026-07-06 17:27:33 +08:00
李通洲 ec25659503 Presets: uses the builtin icons in examples/10 to avoid inconsistency [ci skip]
Fixes #2438
2026-07-05 08:16:55 +08:00
Carter Li 35dbcb2588 CI: updates scripts 2026-07-04 18:49:00 +08:00
Carter Li 8b6a74f2ec Doc: update changelog 2026-07-03 16:18:01 +08:00
Carter Li 2ea6c3767e Logo (Builtin): cleanup a lot of distro names 2026-07-03 16:15:58 +08:00
Carter Li 827bc26b0a Trace: removes useless empty lines 2026-07-03 15:40:32 +08:00
Carter Li e12f3631d4 OS (Linux): fixes potencial issue 2026-07-03 15:37:38 +08:00
Carter Li 52c9730542 Tracer: query tid only when threading is enabled 2026-07-03 15:36:41 +08:00
Carter Li 225d9e7771 Release: v2.65.3 2026-07-03 14:50:59 +08:00
Carter Li d031d6c20f FFPlatform (Windows): hard codes i686 CPU arch 2026-07-03 14:36:18 +08:00
李通洲 35af768d92 Shell (Windows): improves performance of Windows PowerShell version detection 2026-07-03 11:07:15 +08:00
Carter Li 22c4620345 Logo (Builtin): adds Azure Linux
Fixes #2435
2026-07-03 09:45:34 +08:00
Carter Li 81738aa303 WM (Linux): fixes compatibility with WSL 2.9.3+ 2026-07-02 17:34:43 +08:00
Carter Li 113f7d34d8 OS (Linux): Add Astra Linux version detection
Fixes #2427
2026-07-01 10:57:01 +08:00
Carter Li 62513004c8 Logo (Builtin): adds Flatcar 2026-07-01 10:29:47 +08:00
Carter Li 1b36c3cd5f Logo (Builtin): updates c.inc 2026-07-01 10:29:47 +08:00
eepy 78874ae583 Logo: add chimera2, parabola2_small, postmarketos2, qubes_small (#2430)
* Logo: add chimera2, parabola2_small, postmarketos2, qubes_small

* Logo: add types to chimera2, parabola2_small, postmarketos2, qubes_small, remove "parabola-gnulinux"

* Change logo names to use capital letters

---------

Co-authored-by: v_v <circlepuller@inbox.lv>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-06-30 21:29:39 -05:00
李通洲 a447928853 FFstrbuf: don't try to inline functions with varargs 2026-06-30 19:35:34 +08:00
李通洲 9f446bdad7 Common (Library): adds fast path for loading only one lib 2026-06-30 19:35:34 +08:00
李通洲 4cf060eb27 Logo (Image): improves performance of DLL searching on WIndows 2026-06-30 19:35:34 +08:00
Carter Li 08d419d75c Global: adds a simple tracer 2026-06-30 16:19:57 +08:00
Carter Li 3ae1bfdc24 Media (macOS): uses perl for faster startup 2026-06-30 15:22:19 +08:00
李通洲 0e257f25c2 Platform (Windows): one less syscall 2026-06-30 09:03:00 +08:00
Carter Li 195e148cc1 Common: inlines more functions 2026-06-30 09:03:00 +08:00
Carter Li 5ab192ee05 Common (Thread): adds ffThreadGetCurrentId 2026-06-30 00:39:36 +08:00
weedygmd 4897152af6 Logo: adds chimera linux small logo (#2426)
* added small chimera linux logo

* Add logo type for Chimera_small

---------

Co-authored-by: Weed <weedygmd>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-06-29 00:36:10 -05:00
Carter Li 69418cb527 Packaging: updates debian stuff [ci skip] 2026-06-29 10:12:54 +08:00
李通洲 0e90f3a7d4 GPU (Windows): fixes typo 2026-06-28 17:07:48 +08:00
Carter Li 1a663e72da Release: v2.65.2 (#2425) 2026-06-28 03:55:56 -05:00
李通洲 e0ae1ac1a2 GPU (Intel): adds comments 2026-06-28 16:26:00 +08:00
李通洲 e0d141ecf6 Memory (BSD): adds underflow protection (should not happen) 2026-06-28 16:25:08 +08:00
李通洲 29eb8bb57d Chore: fixes typos 2026-06-28 16:25:07 +08:00
李通洲 bc1f240558 Memory (Linux): uses strtoull to avoid overflow in 32-bit systems 2026-06-28 16:25:07 +08:00
李通洲 3e15a2591a Release: v2.65.2 2026-06-28 16:25:07 +08:00
李通洲 0ec9443de5 Logo (Builtin): adds Turkish
Fixes #2421
2026-06-28 16:25:07 +08:00
李通洲 4a4ca9a4a8 Memory (NetBSD): takes ZFS arc bytes into account
Used logic from FreeBSD
2026-06-28 16:25:07 +08:00
李通洲 acf76e565a Memory (FreeBSD): don't query c_min if querying size fails 2026-06-28 16:25:07 +08:00
李通洲 778aa21192 Memory (SunOS): takes ZFS arc bytes into account 2026-06-28 16:25:07 +08:00
Carter Li dfdc7284a2 Memory (Linux): takes ZFS arc bytes into account
Fixes #1995
2026-06-28 16:25:07 +08:00
Carter Li 231d7fcd4d Memory (FreeBSD): takes ZFS arc bytes into account
Fixes #2418
2026-06-28 16:25:07 +08:00
Carter Li a3184601dc GPU: detects PCIe speed only in driverSpecific mode
Fixes #2419
2026-06-28 16:25:07 +08:00
李通洲 e3dfeeb8db GPU (MT): adds PCIe speed detection support 2026-06-27 09:46:30 +08:00
Carter Li ccdcd6ab6f Codec (Linux): fixes crashing on AMD GPUs
Ref: https://github.com/fastfetch-cli/fastfetch/issues/2419#issuecomment-4812121503
2026-06-27 08:12:22 +08:00
Carter Li 64d205628e Common (Settings): adds SQLITE_OPEN_NOMUTEX fiag when opening sqlite db 2026-06-26 22:52:59 +08:00
Carter Li ff13adf1b4 Logo (Builtin): updates CachyOS 2026-06-26 00:18:08 +08:00
iinsert c38fd9ec10 Chore: adds Catnap repo link to attribution comments in examples 13-16 (#2417) 2026-06-25 23:07:49 +08:00
Carter Li 96793ec604 Packaging: updates debian stuff [ci skip] 2026-06-24 14:28:35 +08:00
Carter Li b79a336576 Release: 2.65.1
Revision to make github happy
2026-06-24 10:21:03 +08:00
Carter Li d36e3a793b Merge pull request #2410 from fastfetch-cli/dev
Release v2.65.0
2026-06-23 20:39:21 -05:00
Carter Li d48bb48e4f Codec (Linux): fixes potential memleaks 2026-06-24 08:45:45 +08:00
李通洲 835001eb2f Doc: updates changelog 2026-06-23 15:51:42 +08:00
李通洲 5647703e4d WM (Linux): adds weston detection support 2026-06-23 15:51:42 +08:00
李通洲 eff0108bb5 Codec (Linux): adds va-x11 method 2026-06-23 15:33:58 +08:00
Carter Li 31c1431ac6 Release: v2.65.0 2026-06-23 13:16:49 +08:00
Carter Li fa2c56cb9f Global: fixes bugs found by CI
The code quality is to be improved...
2026-06-23 13:16:49 +08:00
Carter Li 104b33c1f7 Display: defaults disableLinewrap to false 2026-06-23 11:05:11 +08:00
Gretagen ZETA cb4502dacc Logo (Builtin): adds Zerene OS mainline (#2404)
* Create zerene.txt

* Update z.inc

* Fixed z.inc

Changed the problematic line mismatch

* Update z.inc

* Update z.inc

more fixes to z.inc

* Remove duplicate name entry for Zerene logo

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-06-22 20:24:55 +08:00
Carter Li 3dc86391ab Doc: update changelog [ci skip] 2026-06-22 16:11:44 +08:00
Carter Li f5a67b25f4 Packages (Linux): cleanups install-release package count code 2026-06-22 13:28:18 +08:00
Jess d8be61411e Packages (Linux): add install-release package count support (#2342)
* feat: add install-release package count support

* Apply suggestion from @codacy-production[bot]

Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com>

* Fix formatting of ffParsePropFileValues call

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com>
2026-06-22 00:23:21 -05:00
Carter Li 61968ca95c Chore: tidy 2026-06-22 13:18:27 +08:00
Carter Li 9f190b46c9 DisplayServer (macOS): detects string serial number for Apple Silicon 2026-06-22 13:18:27 +08:00
Kerem Gökcek a6aac70a5e Packages (Linux): Improve emerge detection speed (#2406)
* Packages (Linux): Improve emerge detection speed

* Fix code styling
2026-06-21 21:56:01 -05:00
yabobay 3aa43212ff Packages (Linux): support porg 2026-06-22 10:45:08 +08:00
李通洲 7c39b64fb4 CMake: extracts package managers from source code 2026-06-20 19:24:19 +08:00
Carter Li e1963e41be Networking (Linux): don't use MSG_DONTWAIT to send HTTP request
Ref #2401
2026-06-20 10:17:04 +08:00
Carter Li a1d4cbf67f DisplayServer (Wayland): correctly reports platform api 2026-06-20 08:59:31 +08:00
Carter Li f5b9e09d91 DisplayServer (macOS): detects string serial number 2026-06-20 01:21:39 +08:00
Carter Li 9742dda795 Wifi (FreeBSD): adds WPA version detection support 2026-06-19 23:30:01 +08:00
Carter Li 677c213397 Codec (Linux): fixes bug in ffDetectCodecByVdpau 2026-06-19 23:02:13 +08:00
李通洲 8f0a12323b Doc: updates changelog 2026-06-19 20:30:32 +08:00
李通洲 b49f0b3d9c Fastfetch: improves error message for config errors 2026-06-19 20:19:50 +08:00
李通洲 bc686b2c84 Logo: improves error message for chafa options 2026-06-19 20:14:58 +08:00
Carter Li 7c2f7fa4f2 DisplayServer (Linux): detects preferred resolution from EDID 2026-06-19 19:21:00 +08:00
Carter Li 5fd059827d Display: fetch text serial if available instead of the 4-byte integer 2026-06-19 18:56:08 +08:00
Carter Li 240928138e GPU: adds egl-ext detection method 2026-06-18 21:03:28 +08:00
Carter Li 508a50f803 OpenGL (EGL): optimises code 2026-06-18 21:03:28 +08:00
Carter Li bd40d8756e GPU (FreeBSD): adds a missing var-init 2026-06-18 19:33:40 +08:00
Carter Li b732e0c6d7 Codec (Linux): fixes a crash 2026-06-18 18:11:48 +08:00
Carter Li 96685b7ebe Global: cleanups FF_HAVE_DRM macro 2026-06-18 17:45:19 +08:00
Carter Li 49a1e42efd CI: updates spellcheck 2026-06-18 13:39:56 +08:00
Carter Li b0fd11fcbd Global: simplifies code 2026-06-18 10:59:36 +08:00
Carter Li b6127ff2c9 Codec (Linux): removes usage of libdrm 2026-06-18 10:56:28 +08:00
Carter Li f3babe3187 Codec (Linux): fixes memleaks 2026-06-18 10:44:11 +08:00
Carter Li e9c0d886d1 DisplayServer (Linux): be compatible with KDE 6.7
This PR also removes usage of `kde-output-order-v1-protocol`, which disables detection of primary monitor for old KDE versions
2026-06-18 10:31:37 +08:00
Carter Li d6a4946511 DisplayServer (Linux): fixes memleaks 2026-06-18 10:06:52 +08:00
Carter Li 43e0cc22ff GPU: initializes pcieSpeed everywhere 2026-06-18 08:44:01 +08:00
Carter Li c42ea6eeea DisplayServer (Linux): adds HDR detection support
Fixes #2356
2026-06-17 20:07:37 +08:00
Carter Li fe7962d5d2 DisplayServer (Linux): embeds definitions of wl-output-* 2026-06-17 15:32:27 +08:00
Carter Li e84195bca0 Linux (Wayland): drops zwlr-output.c
It doesn't expose much more functions than `wl-output`
2026-06-17 15:10:24 +08:00
Carter Li bf0133fe60 Packaging: updates debian stuff [ci skip] 2026-06-17 15:06:15 +08:00
李通洲 942c15b7b0 CPU (X86): fixes detection for AMD Carrizo
Ref: https://github.com/anrieff/libcpuid/commit/b0c4959cf4a8b8351ab33add3f83ee0dcf37faf1
2026-06-15 18:41:48 +08:00
Carter Li 61a0bbcc8d GPU (Linux): fixes building for old kernel headers 2026-06-14 19:51:30 +08:00
Carter Li 8b3673eb38 GPU (Nvidia): replaces deprecated API nvmlDeviceGetTemperature with suggested one 2026-06-14 19:51:30 +08:00
Carter Li 22f9948497 GPU: detect current pcie link speed 2026-06-14 19:51:30 +08:00
李通洲 107f39eb15 JsonSchema: update moduleFormat 2026-06-14 19:51:30 +08:00
Carter Li 4e44c0520b GPU: detects max PCI gen & link width 2026-06-14 19:51:29 +08:00
Carter Li 55eb3c59d4 GPU (Linux): replaces amdgpu library with raw ioctl calls 2026-06-14 19:51:29 +08:00
Carter Li 878ccf1375 DisplayServer (Linux): use kernel headers if libdrm is not available 2026-06-13 12:29:51 +08:00
Carter Li ebb0cf77bd CMake: checks linux kernel headers 2026-06-13 12:29:51 +08:00
Carter Li 17914dc29e Global: unifies FF_STR macro 2026-06-13 12:29:51 +08:00
李通洲 14dfe171fb GPU (OpenBSD): adds DRM method 2026-06-13 12:29:51 +08:00
Carter Li 265c334399 GPU (FreeBSD): moves DRM detection to global space for OpenBSD use 2026-06-13 12:29:51 +08:00
Carter Li fc303c58db GPU: adds unified ffGPUFillVendorByDeviceName 2026-06-13 12:29:51 +08:00
Carter Li 01e7503263 GPU (BSD): uses direct ioctl calls (WIP) 2026-06-13 12:29:50 +08:00
Carter Li ffd0455fe3 DisplayServer (Linux): rewrites libdrm calls with plain ioctls 2026-06-12 14:34:36 +08:00
Carter Li 7df2ed2251 Packages: reorders package variables in custom format 2026-06-12 14:34:36 +08:00
Carter Li 2edc41dd9a CI (OpenBSD): updates packages 2026-06-11 15:14:39 +08:00
Carter Li cada77163e Chore: update .gitignore 2026-06-11 15:07:47 +08:00
Carter Li 7cecdb0e6d DisplayServer (Linux): don't return success if no devices are successfully connected 2026-06-11 10:49:07 +08:00
Carter Li 420a9e9d7b TerminalFont (Linux): adds kmscon support
Fixes #2393
2026-06-11 10:49:00 +08:00
Carter Li b96d8ad00b Terminal (Linux): adds kmscon version detection support 2026-06-11 10:15:50 +08:00
Carter Li 52970e2d13 Processing (Linux): don't use /proc/pid/exe as exePath when the file is not executable (no permission) 2026-06-11 10:15:50 +08:00
Carter Li 4594734b66 CI (OpenBSD): updates OS version 2026-06-09 16:07:56 +08:00
Carter Li eb54c89b4a OS (macOS): adds the code name of macOS 27 2026-06-09 14:05:23 +08:00
Carter Li 43301afc47 CPU: enables showPeCoreCount by default 2026-06-09 14:04:54 +08:00
Carter Li 09e28451ec CPU (Linux): simplifies code of frequency detection 2026-06-09 13:38:49 +08:00
Carter Li 35c2f8c924 CPU (Linux): fixes physical core detection on non-x86 2026-06-09 13:09:58 +08:00
李通洲 3ec7e94b47 CPU (Windows): uses a better way to fetch core types 2026-06-08 19:03:23 +08:00
Carter Li a720e1f945 Fastfetch (Windows): moves SetConsoleMode and SetConsoleOutputCP to the start of process
Fixes #2383
2026-06-08 10:58:14 +08:00
Carter Li 70061625f7 Chore: adds FF_A_COLD 2026-06-08 10:38:28 +08:00
李通洲 5cd4316f98 CPU (X86): uses normalized cpu brand name for pattern matching 2026-06-08 00:41:08 +08:00
李通洲 e946861eb0 Codec (Windows): fixes compatibility of Win 8.1 2026-06-08 00:41:01 +08:00
李通洲 f09aebecd5 CPU (X86): updates comments 2026-06-07 16:48:15 +08:00
李通洲 8f266eb2a7 Chore: don't check spelling in cpu_x86.c 2026-06-07 16:41:59 +08:00
李通洲 8ee08d0067 CI: don't run heavy tests if the light one failed 2026-06-07 16:40:40 +08:00
李通洲 e936ddef6b CPU (X86): adds code name and tech detection
Fixes #1501
2026-06-07 10:46:37 +08:00
李通洲 c706201282 Global: adds some always_inline 2026-06-06 23:01:18 +08:00
李通洲 e24e3b6b29 Global: returns false when an error is printed 2026-06-05 22:34:53 +08:00
李通洲 135547fd50 Logo: don't accept chafa options when chafa is disabled 2026-06-05 22:19:35 +08:00
李通洲 da05bed32f CMake: exposes pre-defined macros to fastfetch.c to avoid imcompatiblity with libfastfetch 2026-06-05 22:19:35 +08:00
Carter Li 636471c366 Merge pull request #2375 from fastfetch-cli/dev
Release v2.64.2
2026-06-05 18:36:58 +08:00
李通洲 cbc84fda6c Common (Lua): addresses AI's feedback 2026-06-05 18:21:28 +08:00
李通洲 fc7a0a8484 Codec (Linux): supports BINARY_LINK_TYPE=dynamic 2026-06-05 18:05:54 +08:00
李通洲 4d3b6c3b1b Common (QJS): supports BINARY_LINK_TYPE=dynamic 2026-06-05 17:49:49 +08:00
李通洲 70e67177fe Common (Lua): supports BINARY_LINK_TYPE=dynamic 2026-06-05 17:22:16 +08:00
李通洲 9fe7d6dbfa Logo: addresses review comments of AI 2026-06-05 16:34:02 +08:00
Carter Li a139a8c4a5 Doc: updates changelog [ci skip] 2026-06-05 16:22:04 +08:00
Valeriy Kosikhin da568c986e Logo (Builtin): update OpenWrt logo
Update the large logo for OpenWrt based on the official branding.
Add a small logo version.
Keep the old logo as openwrt_old.txt

Signed-off-by: Valeriy Kosikhin <vkosikhin@gmail.com>
2026-06-05 16:15:46 +08:00
Carter Li 727fbc0276 Doc: updates changelog 2026-06-05 15:29:00 +08:00
Carter Li 20aabdfd78 Global: resets keysHeight after every refresh 2026-06-05 15:27:25 +08:00
Carter Li e79aaf5ce1 Global: don't clear line in --logo-position right 2026-06-05 15:27:15 +08:00
Carter Li 53c2d07161 Release: v2.64.2 2026-06-05 14:51:50 +08:00
Carter Li 6b9f594620 Global: prevents ascii logo from being overwritten in --dynamic-interval mode 2026-06-05 14:47:01 +08:00
Carter Li ba3968784f Logo (Image): fixes image renders but quickly gets wiped
Regression from v2.64.0

Fixes: #2374
2026-06-05 13:12:07 +08:00
Carter Li 021ece1681 Merge pull request #2370 from fastfetch-cli/dev
Release: v2.64.1
2026-06-04 23:45:19 +08:00
李通洲 9787b56460 Release: v2.64.1 2026-06-04 20:15:54 +08:00
李通洲 54792e61ff Common (Lua): detects circular reference in encode_json 2026-06-04 20:15:54 +08:00
Carter Li b34e2a4055 Common (Base64): adds static to internal functions 2026-06-04 17:22:24 +08:00
Carter Li 3b56200ee4 Packages: adds option PACKAGES_REMOVE_DISABLED to remove disabled package managers from the build entirely 2026-06-04 17:22:24 +08:00
Carter Li de95a62e2f Codec (macOS): removes usage of JPEG XL; replaces enums with raw constants 2026-06-04 10:48:01 +08:00
Carter Li 72cb64a500 Common (Lua): optimises code; fixes incompatibility against lua 5.3 2026-06-04 10:48:01 +08:00
Carter Li d48bd733f0 Merge pull request #2368 from fastfetch-cli/dev
Release v2.64.0
2026-06-03 19:18:31 +08:00
李通洲 0585ea7797 Doc: update changelog 2026-06-03 18:34:09 +08:00
李通洲 794035f8d9 Shell: sets pretty name of busybox to ash 2026-06-03 18:29:33 +08:00
李通洲 723552f68b Shell: be more robust on busybox version detection 2026-06-03 18:29:10 +08:00
Carter Li 8dd38f5744 Release: v2.64.0 2026-06-03 16:04:00 +08:00
Carter Li 616a5c7aea Codec (Vulkan): be compatible with old Vulkan headers
Fixes #2367
2026-06-03 15:23:42 +08:00
Carter Li 5e1e94473e Bootmgr (macOS): don't hard-code the firmware name 2026-06-03 15:23:42 +08:00
CicaDATA 4eae8ac244 Logo (Builtin): updates NurOS logo and colors (#2366) 2026-06-03 02:21:23 -05:00
李通洲 8aeb7c2f10 Shell (Linux): improves performance of busybox (ash) version detection 2026-06-02 17:44:55 +08:00
Carter Li c20b532c7a Common (Format): adds | for center aligning 2026-06-02 16:03:04 +08:00
Carter Li 3c59161aca Common (Format): handles ANSI escapes when padding/truncating variable strings
Fixes #2364
2026-06-02 15:55:10 +08:00
Carter Li bd454632c3 FFstrbuf: inlines more functions 2026-06-02 15:42:40 +08:00
Carter Li e73adc27a0 Common: fixes wcwidth handling 2026-06-02 15:05:13 +08:00
Carter Li 15c6014c04 Common: don't inline ffUtf8CharLenWidth 2026-06-02 14:01:59 +08:00
Carter Li 54f18982ac Common: renames arrayUtil to arrutil 2026-06-02 10:59:18 +08:00
Carter Li 99c2f2a2c8 JsonSchema: adds codec 2026-06-02 10:58:57 +08:00
Carter Li 45f35b1c4d Library (Linux): adds simple debug log 2026-06-02 09:27:38 +08:00
Carter Li 428c05b9de Codec (Linux): optimises code 2026-06-02 09:10:55 +08:00
李通洲 23ca6d94ab CI: run codec module 2026-06-02 00:15:42 +08:00
李通洲 9e4e0cb838 Codec (Linux): removes VAEntrypointEncPicture 2026-06-01 23:45:17 +08:00
李通洲 95a370e5a2 Codec (macOS): fixes building 2026-06-01 20:48:59 +08:00
李通洲 e013005f34 Code (Vulkan): fixes compiling 2026-06-01 20:16:30 +08:00
李通洲 92b86f7cbb Codec: shows types only specifed by showType 2026-06-01 19:27:37 +08:00
李通洲 2e4b7baf44 Codec (Android): adds showType support 2026-06-01 19:27:37 +08:00
李通洲 a47ff0b2dc Codec (macOS): adds showType support 2026-06-01 19:27:37 +08:00
李通洲 1f13f6c8f5 Codec (Windows): adds showType support 2026-06-01 19:27:37 +08:00
李通洲 b0bb6fb58e Codec: don't show Unknown 2026-06-01 19:27:37 +08:00
Carter Li 37029dbbe3 Codec (Vulkan): adds showType support 2026-06-01 19:27:37 +08:00
Carter Li 35428606e7 Codec (Linux): adds FFCodecShowOptions; code cleanup 2026-06-01 19:27:37 +08:00
Carter Li 2c65eee00f Common (Lua): adds json_encode 2026-06-01 19:27:37 +08:00
Carter Li a1bf014352 Codec: normalizes platformApi string 2026-06-01 10:34:17 +08:00
Carter Li 412fc94dab WM (Linux): fixes possible segfault when detecting sway version
Fixes #2360
2026-06-01 10:16:26 +08:00
Carter Li b65de28805 Logo (Builtin): adds Quasar
Fixes #2338 #2323
2026-06-01 09:34:32 +08:00
李通洲 bc86c66cdd Codec (Windows): detects encoders detection support via MFT on Win10 or older 2026-06-01 09:16:22 +08:00
李通洲 9afa01812d Codec (Vulkan): disables impl if the vulkan headers are too old to use 2026-06-01 00:15:27 +08:00
李通洲 30a8a94cd2 Chore (Haiku): silences compiler warnings 2026-05-31 23:56:45 +08:00
李通洲 3a54617196 Codec: adds vulkan support 2026-05-31 23:45:20 +08:00
李通洲 3e3a03a233 Codec (Android): adds support 2026-05-31 23:37:50 +08:00
李通洲 b407669b69 JsonSchema: update 2026-05-31 23:37:49 +08:00
李通洲 e14ea926a5 Codec (macOS): adds platformApi 2026-05-31 23:37:49 +08:00
李通洲 9d8f794cb9 Codec (Windows): detects encoder support via d3d12va 2026-05-31 23:37:49 +08:00
Carter Li 825b8b8715 Codec (Linux): adds vdpau fallback impl 2026-05-31 23:37:49 +08:00
Carter Li 0c94fd87db Codec: updates default format 2026-05-31 23:37:49 +08:00
Carter Li 473a08d85c Decoder: renames to Codec and adds encoders detection support 2026-05-31 23:37:49 +08:00
Carter Li ae5132c388 Decoder (macOS): adds support 2026-05-31 23:37:49 +08:00
李通洲 1addcec7a2 Decoder (Linux): adds *nix support 2026-05-31 23:37:49 +08:00
李通洲 e75c37c101 Decoder (Windows): adds support 2026-05-31 23:37:49 +08:00
李通洲 b9ab823f77 Decoder: inits module 2026-05-31 23:37:48 +08:00
François Revol a63d854681 OS (Haiku): Fix warnings 2026-05-31 23:37:35 +08:00
François Revol 576548b15e WMTheme (Haiku): implement 2026-05-31 23:37:35 +08:00
François Revol 3043971259 Brightness (Haiku): Implement 2026-05-31 23:37:35 +08:00
François Revol ccf4f22f8b Bootmgr (Haiku): Preliminary implementation 2026-05-31 23:37:35 +08:00
LibereCode f932db713c Logo (Builtin): Minor tweak NixOS_small logo (#2357)
* [fix]: markdown-link to wiki

* [fix]: fix color at 1 spot

* [fix]: fix color at 1 spot, again

* Revert "[fix]: markdown-link to wiki"

This reverts commit 72f4d11c90.

"Remove unrelated changes"
2026-05-31 01:11:53 +08:00
李通洲 d2e8a8fd9e CMake: renames DISABLE_MODULE_* for MODULE_DISABLE_* to align with PACKAGE_DISABLE_* 2026-05-30 18:37:42 +08:00
李通洲 4c1f7c114a Chore: reports if embedded wcwidth is enabled 2026-05-30 18:27:17 +08:00
SirSputnikWiki 90bbfe195f Terminal (Linux): improves terminal name detection for nix packages (#2352)
* Improved terminal name detection for nix packages

* Improved terminal name detection for nix packages

* Update terminalshell_linux.c

Move ffStrbufStartsWithC(&result->processName, '.') before string comparation, as it's much cheaper.
2026-05-30 10:16:12 +08:00
Carter Li 1689fc81e9 Logo (Builtin): adds Origami and Origami_small
Fixes #2321 #2322
2026-05-29 16:05:53 +08:00
Carter Li 4190dd5a6e Logo (Builtin): adds BerserkArch
Fixes #2324 #2310
2026-05-29 16:05:52 +08:00
Carter Li 074f882d7e Wallpaper (Linux): adds COSMIC support 2026-05-29 15:40:27 +08:00
Carter Li 53102380b8 WMTheme (Linux): adds COSMIC support 2026-05-29 15:40:02 +08:00
李通洲 822bc158ba CMake: changes FF_MODULE_XX to FF_DISABLE_MODULE_XX 2026-05-28 23:14:49 +08:00
李通洲 8fbc29a70c Common (strutil): fixes unit tests 2026-05-28 22:41:47 +08:00
李通洲 0ef677a98c Logo (Builtin): add NixOS2
Fixes #2346
2026-05-28 20:12:46 +08:00
Carter Li 10b0d0ca3e CPU (Android): adds Exynos 2600 2026-05-28 19:20:21 +08:00
Carter Li ec4e820e92 Logo: exports ffLogoPrintDetected 2026-05-28 19:18:35 +08:00
Carter Li 6c09fe49e4 Logo (Builtin): warps logo definitions into #ifdef blocks 2026-05-28 18:42:10 +08:00
Carter Li 1ce6398391 Logo (Builtin): splits built-in logos into individual files 2026-05-28 18:42:10 +08:00
Carter Li d1bf208a92 Chore: renames stringUtils to strutil 2026-05-28 15:58:08 +08:00
Carter Li 7ce1e553b8 CMake: makes default structure configurable via CMake 2026-05-28 15:55:43 +08:00
Carter Li 9c878b6943 Chore: moves /src/data/help.json to /doc 2026-05-28 15:54:17 +08:00
Carter Li 6b9a6fd103 CMake: adds MODULE_<module> options to disable modules 2026-05-28 15:41:14 +08:00
Carter Li 896fe60461 CMake: adds option FF_ENABLE_WCWIDTH 2026-05-28 14:47:09 +08:00
Carter Li dadcccdf26 TerminalShell: code refactor 2026-05-28 10:31:35 +08:00
李通洲 0746af7549 Wifi (Linux): adds comments [ci skip] 2026-05-27 17:11:59 +08:00
Carter Li 88c3b7d118 Common (stringUtil): adds ffUtf8CharLenWidth 2026-05-26 16:11:30 +08:00
Carter Li 173d9695b6 Common: removes using of built-in wcwidth, which is locale-dependent 2026-05-26 16:10:01 +08:00
Carter Li 4b265cd56a Common: adds Attr FF_A_ALWAYS_INLINE 2026-05-26 15:37:17 +08:00
李通洲 1f211cf8d1 Brightness: adds ddcciSleep: null to skip DDC/CI detection 2026-05-24 10:58:10 +08:00
李通洲 bac60357c6 Logo: fixes paddingLeft not working with position: top 2026-05-24 08:39:25 +08:00
李通洲 3a0e188570 CMake (Windows): disables usage of WinRT on GCC
Fixes #2341
2026-05-23 22:49:04 +08:00
李通洲 9d5b40686b Global: really prints --stat at the right border 2026-05-23 09:50:49 +08:00
李通洲 a321cd877e Logo: resets color state after printing logo line 2026-05-23 09:44:03 +08:00
李通洲 5f810de1e0 Logo: overrides the auto detected max-width with the configured width, if set 2026-05-23 09:33:58 +08:00
李通洲 3f0a93d057 Logo: reworks position: top; adds a new option --logo-padding-bottom 2026-05-22 20:26:18 +08:00
Carter Li cbca6a965c Logo: prints ASCII logo line by line 2026-05-22 19:09:34 +08:00
Carter Li fde1195c27 TerminalFont (macOS): fixes fallback font detection of Ghostty; adds Muxy terminal support 2026-05-22 14:20:39 +08:00
Carter Li 9856d97bd1 Common (macOS): unifies AppBundle version detection code 2026-05-22 13:37:48 +08:00
Carter Li 2751737ebe CI: builds with quickjs-ng support 2026-05-22 10:24:25 +08:00
Carter Li 834292df29 Brightness (DFBSD): fixes compiling 2026-05-22 10:09:39 +08:00
Carter Li a9a29869a4 Format: tidy 2026-05-22 10:09:39 +08:00
Carter Li 242fb50461 Format: traits undefined result as an error 2026-05-22 09:26:52 +08:00
Carter Li b5c4ffcc85 Format (Lua): simplifies error messages 2026-05-21 09:25:41 +08:00
李通洲 2c3628c630 Format (QJS): converts UINT64 to double and drops usage of BigInt 2026-05-20 23:01:28 +08:00
李通洲 4cca9bf198 Presets: removes invalid comments 2026-05-20 18:40:36 +08:00
李通洲 0ed27d9700 Format: fixes a possible OOB read 2026-05-20 18:40:20 +08:00
李通洲 9bca4eb48f Format: normalizes arg name before pass to script language 2026-05-20 18:39:12 +08:00
李通洲 462b80fc36 CMake: corrects the package name of quickjs-ng 2026-05-20 18:17:38 +08:00
Carter Li f49620a95b CMake: hardens Lua handling 2026-05-20 16:18:50 +08:00
Carter Li 6e0949c739 CMake: fixes finding quickjs 2026-05-20 09:32:02 +08:00
Carter Li 4b18ab0de7 Brightness (macOS): fixes building 2026-05-20 09:31:35 +08:00
Carter Li 8abd75a746 Brightness: refactor 2026-05-20 00:09:09 +08:00
Carter Li d5b215e074 Brightness (FreeBSD): improves DDC/CI handling 2026-05-20 00:07:20 +08:00
Carter Li 0b22427091 WM (Linux): fixes swayfx version detection on NixOS 2026-05-19 17:20:56 +08:00
Carter Li aa34910b6c CMake: actually compiles with quickjs-ng definitions 2026-05-19 15:52:01 +08:00
李通洲 52972ed833 CI (Windows): bundles dlls of lua & qjs 2026-05-18 11:06:30 +08:00
李通洲 68e75effab CMake: adds comments [ci skip] 2026-05-18 11:01:37 +08:00
Carter Li bb79370d03 Brightness (FreeBSD): adds ddc-ci detection support (WIP) 2026-05-18 10:08:31 +08:00
李通洲 9613cdd146 CI: builds with quickjs support 2026-05-18 01:42:13 +08:00
李通洲 724b816252 CI: builds with lua support 2026-05-17 23:21:49 +08:00
李通洲 7c89a10add Common: adds Lua script support for custom format 2026-05-17 20:12:03 +08:00
李通洲 fb5ec76eb3 Global: skips module if format buffer is empty 2026-05-17 19:55:30 +08:00
Carter Li 7141214f95 WM (Linux): fixes swayfx version detection 2026-05-17 09:51:19 +08:00
Carter Li 7d6074968f Packaging: update debian stuff [ci skip] 2026-05-15 09:40:40 +08:00
Carter Li 3bd380802b Merge remote-tracking branch 'origin/master' into dev 2026-05-15 09:40:24 +08:00
李通洲 ec1200dc06 Media (Windows): removes using of C++20 std::bind_front 2026-05-14 19:50:38 +08:00
Carter Li 5c18c061b3 GPU (Linux): silences a warning in Release mode 2026-05-14 09:39:17 +08:00
Carter Li acf610416c Merge pull request #2331 from fastfetch-cli/dev
Release: v2.63.1
2026-05-13 19:54:48 +08:00
Carter Li 90d3b3d49f Release: v2.63.1 2026-05-13 19:41:21 +08:00
Carter Li bbc5b4de98 Wifi (Linux): disables usage of Netlink on big-endian platforms
Until some can confirm it works
2026-05-13 19:29:33 +08:00
Carter Li 7f9b6187a6 CommandOption: fixes segfault with unknown module 2026-05-13 19:28:36 +08:00
Carter Li 8067e43631 Media (Linux): be compatible with signed media length
Fixes Chrome support
2026-05-13 19:07:14 +08:00
Carter Li 61dba1ea05 Packaging: update debian stuff [ci skip] 2026-05-13 16:04:51 +08:00
Carter Li a94df76bfa Merge pull request #2330 from fastfetch-cli/dev
Release v2.63.0
2026-05-13 16:04:31 +08:00
Carter Li b2b748b07c DisplayServer (Linux): fixes a memory leak 2026-05-13 15:44:00 +08:00
Carter Li 77ce6b0e4c Settings (Linux): shuts libeet down if applicate 2026-05-13 15:33:55 +08:00
Carter Li d28d307b63 Release: v2.63.0 2026-05-13 14:56:22 +08:00
Carter Li 3492f9bfa1 Common (Linux): tidy 2026-05-13 14:38:16 +08:00
李通洲 79c67ec0d7 CI (Linux): installs libefl 2026-05-13 14:37:39 +08:00
Carter Li 6527f03a9b Logo (Builtin): add Ximper Linux
Fixes #2283
2026-05-13 13:53:00 +08:00
Carter Li a8b629f58c DE (Linux): fixes an inverted test 2026-05-13 13:23:23 +08:00
Carter Li 5df00a3394 Global: adds missing #endifs back 2026-05-13 13:14:21 +08:00
Carter Li 8a7c83cac6 Doc: update changelog 2026-05-13 11:08:02 +08:00
Carter Li 27bffb3464 Windows: removes unused config wmiTimeout 2026-05-13 11:07:48 +08:00
李通洲 875afb7cde Media (Windows): adds global.playerName selection support 2026-05-13 10:19:45 +08:00
李通洲 3e99a7035b Media (Windows): adds length & position detection support 2026-05-13 10:19:31 +08:00
Carter Li 63873763de Doc: update JsonSchema [ci skip] 2026-05-13 10:17:06 +08:00
Carter Li 27c83e88f2 Media: prints hours if the song is longer than 1 hour 2026-05-13 10:12:07 +08:00
Carter Li f48904805f Media: fixes percentage format 2026-05-13 10:12:07 +08:00
Carter Li 531cd0909a Media (Linux): don't use playerctld as a media player 2026-05-13 10:12:07 +08:00
李通洲 eafcdfec9e WM (Linux): fixes building 2026-05-12 23:10:09 +08:00
李通洲 d6bd855733 DateTime: adds AM/PM format support to date and time output
Fixes #2325
2026-05-12 22:54:49 +08:00
李通洲 af7e2d47d1 OS (Windows): adds support for Embedded variant in OS detection 2026-05-12 22:54:31 +08:00
Carter Li f71c0b0866 Media: adds progress number & bar format support 2026-05-12 19:14:56 +08:00
Carter Li 1400291ae9 Media (macOS): adds length & position detection support 2026-05-12 15:07:22 +08:00
Carter Li 7799dbe481 WM: adds full support of Enlightenment
Fixes #2165
2026-05-12 10:56:14 +08:00
Carter Li 8426833c36 DE (Linux): adds Enlightenment version detection support 2026-05-12 08:36:50 +08:00
Carter Li 235a2018fc Chore: update .clang-format [ci skip] 2026-05-12 08:36:50 +08:00
李通洲 470e3b4e57 IO (Linux): fixes a possible fd leak 2026-05-12 00:08:27 +08:00
Carter Li 1942dce980 Media (Linux): detects song length & play position 2026-05-11 23:25:52 +08:00
Carter Li efca4f3597 DBus: expands Get(U)Int to (u)int64 2026-05-11 23:24:45 +08:00
Carter Li 43ddbdca85 Logo (Builtin): tidy
Fk `clang-format`
2026-05-11 11:06:01 +08:00
Carter Li 5d29e26509 Logo (Builtin): cleans up Kylin 2026-05-11 11:03:15 +08:00
Carter Li 8daec2568c Common (Windows): adds a missing #include 2026-05-11 10:13:48 +08:00
Carter Li 320e1bf4e0 Doc: update changelog [ci skip] 2026-05-11 09:42:48 +08:00
Carter Li 38e98d3d51 Logo (Builtin): cleans up xj380 2026-05-11 09:37:57 +08:00
HNO₃ 50964fcddf Logo (Builtin): adds openRuyi (#2318)
* Logo: Add openRuyi

* Update ASCII art in openruyi.txt

* Fix casing of 'openRuyi' in builtin.c

---------

Co-authored-by: Z572 <z572@z572.online>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-05-11 09:37:02 +08:00
国企鱼 6c7a8a8c41 Logo (Builtin): adds XJ380 OS Logo (#2309) 2026-05-11 09:36:32 +08:00
Carter Li 92082eed54 Doc: update PR template [ci skip] 2026-05-11 08:56:31 +08:00
Carter Li 26b3a84b8a Terminal: fixes TDE konsole version detection
Fixes #2319
2026-05-11 08:51:46 +08:00
Carter Li 0747fc0887 CI (OmniOS): fixes build 2026-05-10 17:35:33 +08:00
Carter Li 60fbe1fd0b Common (Windows): uses WinRT APIs only when FF_HAVE_WINRT is defined 2026-05-10 16:46:20 +08:00
Carter Li f8667d9faa Doc: updates changelog 2026-05-10 16:20:48 +08:00
Carter Li 1c89bbc34e Chore: clang-format 2026-05-10 16:00:22 +08:00
Carter Li b37f020270 DisplayServer (Linux): binds minimal version to avoid breakage 2026-05-10 15:43:13 +08:00
Carter Li fbc9569e13 DisplayServer (Linux): updates kde-output-device-v2 again 2026-05-10 15:37:03 +08:00
François Revol a923f61115 Wallpaper (Haiku): adds support (#2314)
* Wallpaper (Haiku): Add support

* Refactor wallpaper detection logic and memory handling

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-05-09 20:35:25 -05:00
李通洲 bc0a515998 Common (Windows): works around a compiler optimise bug 2026-05-09 15:43:15 +08:00
李通洲 87d89130ad Common (Windows): fixes Windows 11 detection code 2026-05-09 15:43:15 +08:00
李通洲 f46aa316cb Wifi (Linux): improves protocol reporting 2026-05-09 14:34:23 +08:00
Carter Li fdb5f30cb8 CMake (Linux): removes linux/wireless detection
Always required now
2026-05-09 11:04:39 +08:00
Carter Li 91f1c4db10 Wifi: fixes 60 GHz band detection 2026-05-09 11:01:50 +08:00
Carter Li 44e2948b1d Wifi: adds 6 GHz channels detection 2026-05-09 11:01:05 +08:00
Carter Li b86acf6c36 Wifi (Linux): fixes bugs when multiple BSS exists; adds ioctl fallback 2026-05-09 11:00:40 +08:00
Carter Li 9a15666248 Wifi (Linux): switches to netlink impl 2026-05-08 22:43:16 +08:00
李通洲 f5dfec6dcb Battery (Windows): tidy
Co-authored-by: Copilot <copilot@github.com>
2026-05-08 14:31:42 +08:00
Carter Li 8c55c06fa7 OS (Linux): detects bedrock only on Linux 2026-05-06 18:15:57 +08:00
李通洲 8159f473cc Common (Windows): allows COM be used in C sources 2026-05-06 15:01:40 +08:00
李通洲 dca3b154ef Global (Windows): fixes possible use-before-init errors 2026-05-06 15:00:52 +08:00
李通洲 79b61f1391 Common (Windows): inits WinRT/COM globally 2026-05-06 14:38:10 +08:00
李通洲 ba54763dde Camera (Windows): adds support for Display P3 color space 2026-05-06 11:06:07 +08:00
Oliver Lin 451bc394ee OS (Linux): enhances Deepin version detection using /etc/os-version (#2300)
* feat(os): enhance Deepin detection with os-version data

Add a Deepin-specific enhancement in Linux OS detection that reads
`/etc/os-version` for `MinorVersion` and `EditionName`.

When available, it now:
- sets `versionID` to `MinorVersion`
- updates `prettyName` to include version and optional edition

This improves Deepin version accuracy and provides a clearer OS name
than relying solely on generic `os-release` fields.feat(os): enhance Deepin detection with os-version data

Add a Deepin-specific enhancement in Linux OS detection that reads
`/etc/os-version` for `MinorVersion` and `EditionName`.

When available, it now:
- sets `versionID` to `MinorVersion`
- updates `prettyName` to include version and optional edition

This improves Deepin version accuracy and provides a clearer OS name
than relying solely on generic `os-release` fields.

* fix(os): use distro name when formatting Deepin prettyName

Update Deepin enhancement formatting to build `prettyName` from
`result->name` instead of hardcoding "Deepin". This keeps output
consistent with the detected distro name while still appending version
and edition details.fix(os): use distro name when formatting Deepin prettyName

Update Deepin enhancement formatting to build `prettyName` from
`result->name` instead of hardcoding "Deepin". This keeps output
consistent with the detected distro name while still appending version
and edition details.

* fix(os/linux): guard Deepin minor version override

Only apply Deepin’s `minor` value to `versionID` when an edition is
present and `prettyName` does not already include parenthesized details.
This avoids incorrectly overriding parsed version info in enhanced names.fix(os/linux): guard Deepin minor version override

Only apply Deepin’s `minor` value to `versionID` when an edition is
present and `prettyName` does not already include parenthesized details.
This avoids incorrectly overriding parsed version info in enhanced names.

Co-authored-by: Copilot <copilot@github.com>

* Refactor Deepin enhancement detection logic

* Refactor detectDeepinEnhancement function

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-05-05 20:43:17 -05:00
李通洲 93f9ed1bf5 Wmtheme (Linux): adds NebiDE support
Ref: #2295
2026-05-04 19:44:42 +08:00
Sarp Mateson d9e4389ed4 Logo (Builtin): add NebiOS (#2295)
* added logo with nebisoft's color palette, updated builtin.c

* forgot to update the nebios logo with    color placeholders
2026-05-04 19:42:51 +08:00
李通洲 b465052ad2 Logo (Builtin): removes Ubuntu KDE 2026-05-02 22:19:26 +08:00
李通洲 2e6b9cd503 OS (Linux): adds comments 2026-05-02 22:18:08 +08:00
李通洲 0557f16c16 OS (Linux): adds Ubuntu Unity detection 2026-05-02 22:06:18 +08:00
李通洲 08e252a44c OS (Linux): adds Ubuntu Kylin detection 2026-05-02 21:59:22 +08:00
Oliver Lin 90e2d8f8d9 OS (Linux): detects Ubuntu Studio before Kubuntu on KDE systems (#2298)
* fix(os): detect Ubuntu Studio before KDE-based flavor checks

Add an explicit Ubuntu Studio detection in `getUbuntuFlavour()` by
checking for `/usr/share/doc/ubuntustudio-desktop` and setting
`name`, `id`, and `idLike` accordingly.

This prevents Ubuntu Studio systems from being misidentified as
Kubuntu when KDE/Plasma-related XDG config paths are present.fix(os): detect Ubuntu Studio before KDE-based flavor checks

Add an explicit Ubuntu Studio detection in `getUbuntuFlavour()` by
checking for `/usr/share/doc/ubuntustudio-desktop` and setting
`name`, `id`, and `idLike` accordingly.

This prevents Ubuntu Studio systems from being misidentified as
Kubuntu when KDE/Plasma-related XDG config paths are present.

* refactor(os): detect Ubuntu Studio via package presence
2026-05-02 21:54:33 +08:00
Angelo Verlain 0dd8d80e02 Logo (Builtin): correctly detects GNOME OS (#2296)
* Correctly detect GNOME OS

* Update builtin.c

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-05-02 01:06:47 +08:00
Christopher L Fox Junior 3cddf31987 Add ASCII logo for KibaOS (#2294)
* Add ASCII logo for KibaOS

* Add KibaOS logo to builtin.c

* Update builtin.c

* Update builtin.c

* Add KibaOS logo to builtin logo configurations

Added KibaOS logo configuration to the logo data structure.

* Fix KibaOS Syntax
2026-05-01 17:13:32 +08:00
李通洲 fe1c5c8f6f Media (Windows): improves readability
Co-authored-by: Copilot <copilot@github.com>
2026-05-01 11:58:19 +08:00
李通洲 994bd53d30 Media (Windows): major code refactor
moves detection code into fastfetch binary

Co-authored-by: Copilot <copilot@github.com>
2026-04-30 20:26:57 +08:00
李通洲 383a4190ca Comon (macOS): tidy
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 13:26:46 +08:00
李通洲 42f2e5a745 Netif (macOS): improves reliability 2026-04-30 11:01:07 +08:00
Carter Li 14b8bb2bb5 Temps: validates temp color thresholds as integers in JSON parsing
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 09:33:48 +08:00
Carter Li b68ad3626c Sysctl: returns error on failed string fetch and removes malloc null check
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 09:31:28 +08:00
Carter Li cd25803e32 Option: adds a missing validation 2026-04-30 09:27:05 +08:00
Carter Li 3d6bffe7fe Settings: fixes DBusMessage reply leaks in XFConf functions
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 09:04:02 +08:00
Carter Li e694c8ac84 Properties: fixes a typo
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 08:50:23 +08:00
李通洲 dfff57dd85 Percent: improve reliability
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 08:40:30 +08:00
李通洲 c5141855a2 Path: removes dead code 2026-04-30 08:40:30 +08:00
李通洲 6cb186f229 Parsing: improves reliablity
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 08:40:30 +08:00
李通洲 e91f62aa70 Option: improve reliablity 2026-04-30 08:40:30 +08:00
李通洲 ab5cf94099 Networking: improves reliablity
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 08:40:30 +08:00
李通洲 d9eccd70ed Battery (Windows): removes option useSetupApi 2026-04-29 18:54:18 +08:00
李通洲 025febc78d Battery (Windows): switches to query WMI with NtApi as a fast path
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 18:50:04 +08:00
李通洲 69cc19d6f5 Brightness (Windows): cleanups debug log 2026-04-29 18:42:12 +08:00
李通洲 2e4dd1d262 Chore: silenses compiler warnings 2026-04-29 17:36:37 +08:00
李通洲 24ec0e6035 Common (Windows): removes old COM based WMI query implementation 2026-04-29 00:11:29 +08:00
李通洲 6e50aaf3ff Brightness (Windows): uses COM-less method to query WMI
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 00:11:29 +08:00
李通洲 e7cd5f618d Bluetooth (Windows): uses CM API to detect BTH battery detection
Co-authored-by: Copilot <copilot@github.com>
2026-04-28 19:52:38 +08:00
李通洲 55e4896524 Chore: runs clang-format 2026-04-28 19:45:19 +08:00
李通洲 594c73461e Netif: fixes compiler warnings 2026-04-28 15:19:44 +08:00
Or-simen 94ceeb4482 Chore: fixes typo from FF_UNITIALIZED to FF_UNINITIALIZED (#2290)
Co-authored-by: or sim <you@example.com>
2026-04-27 21:23:42 -05:00
李通洲 4ee7dd72d0 IO: improves code quality & reliablity 2026-04-28 09:03:24 +08:00
李通洲 414f7ce067 Netif: improves code quality
Co-authored-by: Copilot <copilot@github.com>
2026-04-28 08:51:03 +08:00
李通洲 e1dffe794b Library: improves code quality
Co-authored-by: Copilot <copilot@github.com>
2026-04-28 08:51:03 +08:00
李通洲 181b775f73 Init: don't print unecessary ANSI escape codes
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 23:15:30 +08:00
李通洲 c4c934d23e Format: fixes UINT64 handling
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 23:00:52 +08:00
李通洲 31c73543e8 Font: improves pt handling
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 22:57:29 +08:00
李通洲 d79e1d7fbc FFstrbuf: improves robustness of ffStrbufMatchSeparatedNS
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 22:49:31 +08:00
李通洲 3883047dce Platform: initializes pageSize
Noop, because the whole platform is statically initialized

Co-authored-by: Copilot <copilot@github.com>
2026-04-27 22:35:11 +08:00
李通洲 4eebc1b6ee Platform (Windows): adds comments
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 22:30:48 +08:00
李通洲 08b79ff4ae Platform (OpenBSD): silences a compiler warning
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 22:27:10 +08:00
李通洲 ffc38eb0f1 FFlist: add __restrict 2026-04-27 22:21:45 +08:00
李通洲 37ee193c40 DBus: improves message handling 2026-04-27 22:11:34 +08:00
李通洲 c10027f1d7 JsonConfig: fixes CPUUsage preparation never executed
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 21:56:52 +08:00
李通洲 039fa1ba77 CommandOption: generates JSON result entry even for unknown modules
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 20:28:11 +08:00
李通洲 0db820a6c1 Binary: skips short string entirely to improve performance
Co-authored-by: Copilot <copilot@github.com>
2026-04-27 19:51:14 +08:00
tnut 8b611899d1 Packages (Linux): adds cards counting (NuTyX) (#2287)
* Packages:add cards counting (NuTyX)

* package.c
no need to add counts.catds

* Sort packages print alphabetically

* ditto

* ditto

* packages.c
update FF_ARG and ffpackagesModule.info

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-04-27 19:31:08 +08:00
李通洲 ba7e1eb18b Netif (Windows): correctly selects lowest-metric default route on IPv4
... and improve performance slightly
2026-04-26 16:57:38 +08:00
李通洲 6979b1efc5 Dep (3rdparty): upgrades display-library 2026-04-26 16:00:01 +08:00
1325 changed files with 38420 additions and 17478 deletions
+8 -2
View File
@@ -1,7 +1,6 @@
# find . -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" \) ! -path "src/3rdparty/*" -print0 | xargs -0 clang-format -i
# find . -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" -o -name "*.m" -o -name "*.mm" \) -print0 | xargs -0 clang-format -i
BasedOnStyle: LLVM
Language: Cpp
UseTab: Never
IndentWidth: 4
@@ -81,3 +80,10 @@ AttributeMacros:
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: false
---
Language: ObjC
ObjCBlockIndentWidth: 4
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
ObjCBreakBeforeNestedBlockParam: true
+1
View File
@@ -1,2 +1,3 @@
src/3rdparty/**
build/**
src/logo/builtin.c
+2 -2
View File
@@ -1,5 +1,5 @@
[codespell]
check-filenames =
builtin = clear,rare,usage,informal
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h,./src/detection/cpu/cpu_x86.c,./src/detection/gpu/gpu_bsddrm.c,./src/detection/displayserver/linux/wayland/*-protocol.*,./build,./build-*,./build_*,./src/common/impl/genconfig.c
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu,renderD,SME,Carmel,kinda,symbole,connexion,comando,processus,lokale,adres,titel,som,environnement,Sistem,Lokal,Lokal,Sistem,Paket,Hava
+32 -7
View File
@@ -6,16 +6,31 @@ body:
- type: markdown
attributes:
value: |
Tip: You can display a logo in fastfetch without adding it to fastfetch's official repo.
> [!WARNING]
> **NB:** If your logo request does not meet the basic requirements outlined in this template, the issue may be closed at any time without any further explanation.
**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
You can test your logo locally using:
`fastfetch -l /path/to/logo.txt --logo-color-1 white --logo-color-2 red`
Please refer to the [Migration Guide](https://github.com/fastfetch-cli/fastfetch/wiki/Migrate-Neofetch-Logo-To-Fastfetch) for details on color placeholders (`$1`, `$2`, etc.).
- type: textarea
attributes:
label: OS
description: Paste the contents of `/etc/os-release` and `/etc/lsb-release` here. If neither file exists, describe how to identify the distro.
description: Paste the contents of `/etc/os-release` (specifically the `ID` and `PRETTY_NAME` fields). If neither file exists, describe how to identify the distro.
placeholder: cat /etc/os-release
validations:
required: true
- type: input
attributes:
label: Public repository URL
description: A public repository is required to verify the request. Please provide a link to the repository where the distro is developed.
placeholder: https://github.com/example/distro
validations:
required: true
- type: input
attributes:
label: Distro Website
@@ -23,25 +38,35 @@ body:
placeholder: https://example.com
validations:
required: true
- type: textarea
attributes:
label: ASCII Art
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
description: |
The ASCII logo should not take up too much space (smaller than 50x20 characters, W x H).
**Important:** Fastfetch uses `$1`, `$2`, `$3` etc. for color placeholders. Do NOT use hardcoded ANSI escape codes (like `\033[38;2...m`) or Neofetch's `${c1}` syntax.
Take <https://github.com/fastfetch-cli/fastfetch/tree/dev/src/logo/ascii> as examples.
placeholder: Paste ASCII art with $1, $2 placeholders here
validations:
required: true
- type: input
attributes:
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: My distro has reached a stable state (out of beta, alpha, RC).
required: true
- label: The ASCII art is smaller than 50x20 characters (W x H).
required: true
- label: The ASCII art includes color codes, or the color codes are available in `os-release`.
- label: The ASCII art uses `$N` color placeholders (or colors are natively available in `os-release`).
required: true
- label: The ASCII art has no internal padding (spaces at the start and/or end of lines).
- label: The ASCII art has no unnecessary trailing spaces at the end of lines.
required: true
- label: I promise that I will send a removal request if the distro is discontinued.
required: true
+405
View File
@@ -0,0 +1,405 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fastfetch · Benchmark</title>
<style>
:root {
color-scheme: light;
--page: #f5f7fb;
--card: #fff;
--text: #172033;
--muted: #64748b;
--border: #dbe3ef;
--accent: #2563eb;
--accent-soft: #dbeafe;
--chart-text: #334155;
--chart-grid: #cbd5e1;
}
:root[data-theme="dark"] {
color-scheme: dark;
--page: #0f172a; --card: #172033; --text: #e5edf8; --muted: #9aabc1; --border: #334155; --accent-soft: #1e3a8a;
--chart-text: #f1f5f9;
--chart-grid: #475569;
}
* { box-sizing: border-box; }
body { max-width: 1440px; margin: 0 auto; padding: 2.5rem 1.25rem 4rem; background: var(--page); color: var(--text); font: 16px/1.5 system-ui, -apple-system, sans-serif; }
header { margin-bottom: 1.75rem; }
.header-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
h1 { margin: 0; font-size: clamp(2rem, 4vw, 3rem); letter-spacing: -.04em; }
h2 { margin: 0; font-size: 1.25rem; }
p { color: var(--muted); }
.intro { margin: .6rem 0 1rem; }
.links a { color: var(--accent); font-weight: 600; text-decoration: none; }
.links a:hover { text-decoration: underline; }
.theme-toggle, .fullscreen { border: 1px solid var(--border); border-radius: .55rem; padding: .5rem .8rem; background: var(--card); color: var(--text); cursor: pointer; font: inherit; font-weight: 600; }
.theme-toggle:hover, .fullscreen:hover { border-color: var(--accent); color: var(--accent); }
.tabs { display: flex; flex-wrap: wrap; gap: .6rem; margin: 1.5rem 0; padding: .35rem; border: 1px solid var(--border); border-radius: .8rem; background: var(--card); }
.tab { border: 0; border-radius: .55rem; padding: .65rem 1.15rem; background: transparent; color: var(--muted); cursor: pointer; font: inherit; font-weight: 700; }
.tab:hover, .tab[aria-selected="true"] { background: var(--accent); color: #fff; }
.tab-panel[hidden] { display: none; }
.platform-title { display: flex; align-items: center; gap: .65rem; margin: 1.5rem 0 1rem; }
.platform-title::before { content: ''; width: .35rem; height: 1.4rem; border-radius: 1rem; background: var(--accent); }
.charts { display: flex; flex-direction: column; gap: 1.25rem; }
.chart { min-width: 0; padding: 1.25rem; border: 1px solid var(--border); border-radius: 1rem; background: var(--card); box-shadow: 0 8px 28px #0f172a0c; }
.chart:fullscreen { overflow: auto; padding: 2rem; background: var(--page); }
.chart:fullscreen .canvas-wrap { height: calc(100vh - 13rem); }
.chart-header { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: .75rem; }
.chart-header span { color: var(--muted); font-size: .85rem; }
.canvas-wrap { position: relative; height: 360px; }
.chart-actions { display: flex; align-items: center; gap: .75rem; }
.legend-actions { display: flex; flex-wrap: wrap; gap: .45rem; margin-top: 1rem; }
.legend-action { border: 1px solid var(--border); border-radius: .45rem; padding: .35rem .6rem; background: var(--card); color: var(--muted); cursor: pointer; font: inherit; font-size: .8rem; }
.legend-action:hover { border-color: var(--accent); color: var(--accent); }
.legend { display: flex; flex-wrap: wrap; gap: .35rem .9rem; margin-top: 1rem; }
.legend-item { display: inline-flex; align-items: center; gap: .4rem; border: 0; padding: .15rem 0; background: transparent; color: var(--text); cursor: pointer; font: inherit; font-size: .85rem; }
.legend-item.is-hidden { color: var(--muted); }
.legend-swatch { width: .75rem; height: .75rem; border-radius: 50%; }
.legend-item.is-hidden .legend-swatch { opacity: .35; }
.chart-tooltip { position: fixed; z-index: 1000; pointer-events: none; width: min(90vw, 900px); max-height: calc(100vh - 24px); overflow: hidden; padding: .7rem .85rem; border: 1px solid var(--border); border-radius: .6rem; background: var(--card); color: var(--text); box-shadow: 0 10px 30px #0f172a33; font-size: .8rem; opacity: 0; transition: opacity .1s ease; }
.chart-tooltip-title { margin-bottom: .35rem; font-weight: 700; white-space: normal; overflow-wrap: anywhere; }
.chart-tooltip-body { max-height: calc(100vh - 76px); overflow: auto; columns: 220px auto; column-gap: 1.5rem; }
.chart-tooltip-row { display: flex; align-items: center; gap: .45rem; break-inside: avoid; white-space: nowrap; }
.chart-tooltip-swatch { width: .55rem; height: .55rem; border-radius: 50%; flex: 0 0 auto; }
.empty { padding: 2rem 0; color: var(--muted); }
</style>
<script src="https://cdn.jsdelivr.net/npm/chart.js/dist/chart.umd.min.js"></script>
<script src="data.js"></script>
</head>
<body>
<header>
<div class="header-row">
<h1>Fastfetch Benchmark</h1>
<button id="theme-toggle" class="theme-toggle" type="button"></button>
</div>
<p class="intro">Performance history grouped by CPU family. Each chart contains all modules and total process time for one operating system and architecture. Module curves are available from the legend and hidden by default.</p>
<p class="links"><a href="data.js">Download raw benchmark data</a></p>
</header>
<nav id="tabs" class="tabs" aria-label="CPU architecture"></nav>
<main id="panels"></main>
<script>
(() => {
const benchmarkData = window.BENCHMARK_DATA || {};
const entries = Object.values(benchmarkData.entries || {}).flat();
const groups = new Map();
function architectureFamily(arch) {
const normalized = arch.toLowerCase();
if (/^(amd64|x86_64|x86|i[3-6]86)$/.test(normalized)) return 'Intel';
if (/^(aarch64|arm64|armv[5-8].*|arm)$/.test(normalized)) return 'ARM';
return 'Other';
}
function parseName(name) {
let match = name.match(/^fastfetch (linux|macos|windows) ([^ ]+) (module .+|total process time)$/i);
if (match) {
return { platform: match[1].toLowerCase(), arch: match[2], metric: match[3] };
}
// Keep older macOS records visible while new records use the platform field.
match = name.match(/^fastfetch ([^ ]+) (module .+|total process time)$/i);
return match ? { platform: 'macos', arch: match[1], metric: match[2] } : null;
}
function entryMetadata(entry) {
const raw = entry.commit && entry.commit.timestamp || entry.date;
const date = new Date(raw);
return {
date: Number.isNaN(date.valueOf()) ? String(entry.date || '') : date.toISOString(),
sha: entry.commit && entry.commit.id ? entry.commit.id : 'unknown'
};
}
for (const entry of entries) {
const metricsByGroup = new Map();
for (const bench of entry.benches || []) {
const parsed = parseName(bench.name);
if (!parsed) continue;
const key = `${parsed.platform} ${parsed.arch}`;
if (!metricsByGroup.has(key)) metricsByGroup.set(key, new Map());
metricsByGroup.get(key).set(parsed.metric, bench.value);
}
for (const [key, metrics] of metricsByGroup) {
if (!groups.has(key)) groups.set(key, []);
groups.get(key).push({ ...entryMetadata(entry), metrics });
}
}
const colors = [
'#2563eb', '#dc2626', '#16a34a', '#9333ea', '#ea580c', '#0891b2',
'#db2777', '#65a30d', '#4f46e5', '#ca8a04', '#0f766e', '#be123c'
];
const tabs = document.getElementById('tabs');
const panels = document.getElementById('panels');
const root = document.documentElement;
const themeToggle = document.getElementById('theme-toggle');
const savedTheme = localStorage.getItem('fastfetch-benchmark-theme');
let theme = savedTheme || (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
const chartsByInstance = [];
function chartColors() {
const styles = getComputedStyle(root);
return {
text: styles.getPropertyValue('--chart-text').trim(),
grid: styles.getPropertyValue('--chart-grid').trim()
};
}
function externalTooltipHandler(context) {
const { chart, tooltip } = context;
let tooltipElement = chart.canvas.parentNode.querySelector('.chart-tooltip');
if (!tooltipElement) {
tooltipElement = document.createElement('div');
tooltipElement.className = 'chart-tooltip';
chart.canvas.parentNode.appendChild(tooltipElement);
}
if (tooltip.opacity === 0) {
tooltipElement.style.opacity = '0';
return;
}
tooltipElement.replaceChildren();
const title = document.createElement('div');
title.className = 'chart-tooltip-title';
const row = chart._benchmarkRows[tooltip.dataPoints[0].dataIndex];
title.textContent = `${new Date(row.date).toLocaleString()} · ${row.sha}`;
tooltipElement.appendChild(title);
const bodyElement = document.createElement('div');
bodyElement.className = 'chart-tooltip-body';
for (const body of [...tooltip.dataPoints].sort((a, b) => b.parsed.y - a.parsed.y)) {
const item = document.createElement('div');
item.className = 'chart-tooltip-row';
const swatch = document.createElement('span');
swatch.className = 'chart-tooltip-swatch';
swatch.style.background = body.dataset.borderColor;
const value = document.createElement('span');
value.textContent = `${body.dataset.label}: ${body.formattedValue} ms`;
item.append(swatch, value);
bodyElement.appendChild(item);
}
tooltipElement.appendChild(bodyElement);
const canvasRect = chart.canvas.getBoundingClientRect();
const margin = 12;
let left = canvasRect.left + tooltip.caretX + margin;
let top = canvasRect.top + tooltip.caretY + margin;
tooltipElement.style.left = `${left}px`;
tooltipElement.style.top = `${top}px`;
tooltipElement.style.opacity = '0';
const tooltipRect = tooltipElement.getBoundingClientRect();
if (left + tooltipRect.width > window.innerWidth - margin) left = canvasRect.left + tooltip.caretX - tooltipRect.width - margin;
if (top + tooltipRect.height > window.innerHeight - margin) top = canvasRect.top + tooltip.caretY - tooltipRect.height - margin;
tooltipElement.style.left = `${Math.max(margin, left)}px`;
tooltipElement.style.top = `${Math.max(margin, top)}px`;
tooltipElement.style.opacity = '1';
}
function updateTheme() {
root.dataset.theme = theme;
themeToggle.textContent = theme === 'dark' ? '☀ Light mode' : '☾ Dark mode';
themeToggle.setAttribute('aria-label', `Switch to ${theme === 'dark' ? 'light' : 'dark'} mode`);
const colors = chartColors();
Chart.defaults.color = colors.text;
Chart.defaults.borderColor = colors.grid;
for (const chart of chartsByInstance) {
chart.options.scales.x.title.color = colors.text;
chart.options.scales.x.ticks.color = colors.text;
chart.options.scales.x.grid.color = colors.grid;
chart.options.scales.y.title.color = colors.text;
chart.options.scales.y.ticks.color = colors.text;
chart.options.scales.y.grid.color = colors.grid;
chart.update();
}
}
themeToggle.addEventListener('click', () => {
theme = theme === 'dark' ? 'light' : 'dark';
localStorage.setItem('fastfetch-benchmark-theme', theme);
updateTheme();
});
updateTheme();
const families = new Map();
for (const [key, rows] of groups) {
const arch = key.slice(key.lastIndexOf(' ') + 1);
const family = architectureFamily(arch);
if (!families.has(family)) families.set(family, []);
families.get(family).push({ key, rows });
}
const familyOrder = ['Intel', 'ARM', 'Other'];
const availableFamilies = familyOrder.filter(family => families.has(family));
for (const [index, family] of availableFamilies.entries()) {
const tab = document.createElement('button');
const panelId = `panel-${family.toLowerCase()}`;
tab.className = 'tab';
tab.type = 'button';
tab.id = `tab-${family.toLowerCase()}`;
tab.setAttribute('role', 'tab');
tab.textContent = family;
tab.setAttribute('aria-controls', panelId);
tab.setAttribute('aria-selected', index === 0 ? 'true' : 'false');
tabs.appendChild(tab);
const panel = document.createElement('section');
panel.className = 'tab-panel';
panel.id = panelId;
panel.setAttribute('role', 'tabpanel');
panel.hidden = index !== 0;
panel.setAttribute('aria-labelledby', tab.id);
const title = document.createElement('h2');
title.className = 'platform-title';
title.textContent = `${family} processors`;
panel.appendChild(title);
const chartGrid = document.createElement('div');
chartGrid.className = 'charts';
panel.appendChild(chartGrid);
panels.appendChild(panel);
tab.addEventListener('click', () => {
for (const otherTab of tabs.children) otherTab.setAttribute('aria-selected', otherTab === tab ? 'true' : 'false');
for (const otherPanel of panels.children) otherPanel.hidden = otherPanel !== panel;
});
for (const { key, rows } of families.get(family).sort((a, b) => a.key.localeCompare(b.key))) {
rows.sort((a, b) => a.date.localeCompare(b.date));
const metrics = [...new Set(rows.flatMap(row => [...row.metrics.keys()]))].sort((a, b) => {
if (a === 'total process time') return -1;
if (b === 'total process time') return 1;
return a.localeCompare(b);
});
const section = document.createElement('article');
section.className = 'chart';
const chartHeader = document.createElement('div');
chartHeader.className = 'chart-header';
const chartTitle = document.createElement('h2');
chartTitle.textContent = key;
const chartActions = document.createElement('div');
chartActions.className = 'chart-actions';
const chartHint = document.createElement('span');
chartHint.textContent = `${rows.length} run${rows.length === 1 ? '' : 's'}`;
const fullscreen = document.createElement('button');
fullscreen.className = 'fullscreen';
fullscreen.type = 'button';
fullscreen.textContent = '⛶ Fullscreen';
fullscreen.addEventListener('click', () => {
if (document.fullscreenElement) document.exitFullscreen();
else section.requestFullscreen();
});
chartActions.append(chartHint, fullscreen);
chartHeader.append(chartTitle, chartActions);
const canvasWrap = document.createElement('div');
canvasWrap.className = 'canvas-wrap';
const canvas = document.createElement('canvas');
canvasWrap.appendChild(canvas);
section.append(chartHeader, canvasWrap);
chartGrid.appendChild(section);
const colorsForChart = chartColors();
const chart = new Chart(canvas, {
type: 'line',
data: {
labels: rows.map(row => row.sha.slice(0, 7)),
datasets: metrics.map((metric, index) => ({
label: metric,
data: rows.map(row => row.metrics.has(metric) ? row.metrics.get(metric) : null),
borderColor: colors[index % colors.length],
backgroundColor: colors[index % colors.length],
pointRadius: 3,
tension: 0.2,
spanGaps: true,
hidden: metric !== 'total process time'
}))
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: { mode: 'index', intersect: false },
plugins: {
legend: { display: false },
tooltip: {
enabled: false,
external: externalTooltipHandler,
callbacks: {
title: tooltipItems => {
const row = rows[tooltipItems[0].dataIndex];
return `${row.date} · ${row.sha}`;
}
}
}
},
scales: {
x: { title: { display: true, text: 'Date', color: colorsForChart.text }, ticks: { color: colorsForChart.text }, grid: { color: colorsForChart.grid } },
y: { beginAtZero: true, title: { display: true, text: 'Milliseconds', color: colorsForChart.text }, ticks: { color: colorsForChart.text }, grid: { color: colorsForChart.grid } }
}
}
});
chart._benchmarkRows = rows;
chartsByInstance.push(chart);
const legendActions = document.createElement('div');
legendActions.className = 'legend-actions';
const legend = document.createElement('div');
legend.className = 'legend';
const legendItems = [];
function refreshLegend() {
legendItems.forEach((item, metricIndex) => {
item.classList.toggle('is-hidden', !chart.isDatasetVisible(metricIndex));
});
}
function setAllLegends(visible) {
metrics.forEach((metric, metricIndex) => chart.setDatasetVisibility(metricIndex, visible));
refreshLegend();
chart.update();
}
function addLegendAction(label, action) {
const button = document.createElement('button');
button.className = 'legend-action';
button.type = 'button';
button.textContent = label;
button.addEventListener('click', action);
legendActions.appendChild(button);
}
addLegendAction('Show all', () => setAllLegends(true));
addLegendAction('Toggle all', () => {
metrics.forEach((metric, metricIndex) => chart.setDatasetVisibility(metricIndex, !chart.isDatasetVisible(metricIndex)));
refreshLegend();
chart.update();
});
addLegendAction('Reset', () => {
metrics.forEach((metric, metricIndex) => chart.setDatasetVisibility(metricIndex, metric === 'total process time'));
refreshLegend();
chart.update();
});
metrics.forEach((metric, metricIndex) => {
const item = document.createElement('button');
item.className = `legend-item${chart.isDatasetVisible(metricIndex) ? '' : ' is-hidden'}`;
item.type = 'button';
item.innerHTML = `<span class="legend-swatch" style="background:${colors[metricIndex % colors.length]}"></span>${metric}`;
item.addEventListener('click', () => {
chart.setDatasetVisibility(metricIndex, !chart.isDatasetVisible(metricIndex));
item.classList.toggle('is-hidden', !chart.isDatasetVisible(metricIndex));
chart.update();
});
legendItems.push(item);
legend.appendChild(item);
});
section.append(legendActions, legend);
}
}
if (!groups.size) {
tabs.hidden = true;
panels.innerHTML = '<p class="empty">No benchmark data available.</p>';
}
})();
</script>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
cooldown:
default-days: 7
open-pull-requests-limit: 10
commit-message:
prefix: "CI"
labels:
- "ci"
groups:
github-actions:
patterns:
- "*"
+4
View File
@@ -21,6 +21,10 @@ Closes #
-
## Screenshots
<!-- Required if this PR introduces visual changes. -->
## Checklist
- [ ] I have tested my changes locally.
+55
View File
@@ -0,0 +1,55 @@
name: Reusable Benchmark
on:
workflow_call:
permissions:
contents: write
jobs:
benchmark:
runs-on: ubuntu-latest
concurrency:
group: benchmark
cancel-in-progress: false
steps:
- name: checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: download benchmark data
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: benchmark-*
path: benchmarks
- name: merge benchmark data
run: jq -s 'add' benchmarks/*/benchmark.json > benchmark.json
- name: save benchmark dashboard
run: cp .github/benchmark-index.html "$RUNNER_TEMP/benchmark-index.html"
- name: store benchmark result
uses: benchmark-action/github-action-benchmark@52576c92bccf6ac60c8223ec7eb2565637cae9ba # v1.22.1
with:
name: Fastfetch
tool: customSmallerIsBetter
output-file-path: benchmark.json
github-token: ${{ secrets.GITHUB_TOKEN }}
ref: ${{ github.sha }}
auto-push: true
summary-always: true
benchmark-data-dir-path: dev/bench
- name: publish benchmark dashboard
run: |
git fetch origin gh-pages
git switch --force-create gh-pages FETCH_HEAD
mkdir -p dev/bench
cp "$RUNNER_TEMP/benchmark-index.html" dev/bench/index.html
git config user.name github-action-benchmark
git config user.email github@users.noreply.github.com
git add dev/bench/index.html
if ! git diff --cached --quiet; then
git commit -m "Update benchmark dashboard"
git push origin gh-pages
fi
+47 -21
View File
@@ -3,38 +3,64 @@ name: Reusable DragonFly amd64
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
shell: cpa.sh {0}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: vmactions/dragonflybsd-vm@v1
- name: Start VM
uses: cross-platform-actions/action@faa0c6197e94aacf1c5956460152c8380d3560a5 # v1.5.0
with:
usesh: yes
envs: 'CMAKE_BUILD_TYPE'
prepare: |
uname -a
pkg update
pkg install -y llvm cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf
operating_system: dragonflybsd
version: '6.4.2'
shell: bash
cpu_count: 4
run: |
env CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: Show system info
run: |
uname -a
pkg --version
- name: Update and install dependencies
run: |
sudo pkg update
sudo pkg install -y llvm cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf lua54 libva libvdpau
- name: CMake configuration
run: env CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_BUILD_TYPE=${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }} .
- name: CMake build
run: cmake --build . --target package --verbose -j4
- name: List features
run: ./fastfetch --list-features
- name: Run normal
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: Run json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: Run flashfetch
run: time ./flashfetch
- name: Run ldd
run: ldd fastfetch
- name: Run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-dragonfly-amd64
path: ./fastfetch-*.*
+47 -22
View File
@@ -3,40 +3,65 @@ name: Reusable FreeBSD amd64
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
shell: cpa.sh {0}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: cross-platform-actions/action@master
- name: Start VM
uses: cross-platform-actions/action@faa0c6197e94aacf1c5956460152c8380d3560a5 # v1.5.0
with:
operating_system: freebsd
architecture: x86-64
cpu_count: 4
version: '15.1'
shell: bash
version: '15.0'
environment_variables: 'CMAKE_BUILD_TYPE'
run: |
uname -a
sudo pkg update
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
cpu_count: 4
- name: Show system info
run: |
uname -a
freebsd-version
pkg -v
- name: Update and install dependencies
run: |
sudo pkg update
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3 egl opencl ocl-icd v4l_compat chafa lua54 libva libvdpau
- name: CMake configuration
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_BUILD_TYPE=${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }} .
- name: CMake build
run: cmake --build . --target package --verbose -j4
- name: List features
run: ./fastfetch --list-features
- name: Run normal
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: Run json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: Run flashfetch
run: time ./flashfetch
- name: Run ldd
run: ldd fastfetch
- name: Run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-freebsd-amd64
path: ./fastfetch-*.*
+40 -20
View File
@@ -3,38 +3,58 @@ name: Reusable Haiku amd64
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
shell: cpa.sh {0}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: cross-platform-actions/action@master
- name: Start VM
uses: cross-platform-actions/action@faa0c6197e94aacf1c5956460152c8380d3560a5 # v1.5.0
with:
operating_system: haiku
version: 'r1beta5'
architecture: x86-64
cpu_count: 4
version: 'r1beta6'
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
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ctest --output-on-failure
cpu_count: 4
- name: Show system info
run: uname -a
- name: Install dependencies
shell: cpa.sh {0} --reboot
run: pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake llvm22_clang ninja pkgconfig python3.10 lua || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake llvm22_clang ninja pkgconfig python3.10 lua
- name: CMake configuration
run: CC=clang CXX=clang++ cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_BUILD_TYPE=${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }} .
- name: CMake build
run: cmake --build . --target package --verbose -j4
- name: List features
run: ./fastfetch --list-features
- name: Run normal
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: Run json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: Run flashfetch
run: time ./flashfetch
- name: Run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-haiku-amd64
path: ./fastfetch-*.*
-40
View File
@@ -1,40 +0,0 @@
name: Reusable Linux armv6l
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: checkout repository
uses: actions/checkout@v6
- name: run VM
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: armv6
distro: bookworm
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y wget
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
with:
name: fastfetch-linux-armv6l
path: ./fastfetch-*.*
+7 -4
View File
@@ -3,6 +3,9 @@ name: Reusable Linux armv7l
on:
workflow_call:
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -11,10 +14,10 @@ jobs:
runs-on: ubuntu-24.04
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: uraimo/run-on-arch-action@v3
uses: uraimo/run-on-arch-action@460cb8e6d9f726a588fc9b5e681c8a6cab09ae41 # v3.2.0
id: runcmd
with:
arch: armv7
@@ -27,7 +30,7 @@ jobs:
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libefl-all-dev liblua5.4-dev libvdpau-dev libva-dev rpm
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -38,7 +41,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-linux-armv7l
path: ./fastfetch-*.*
+40 -8
View File
@@ -14,6 +14,10 @@ on:
description: fastfetch version from linux host build
value: ${{ jobs.build.outputs.ffversion }}
permissions:
security-events: write
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -24,7 +28,7 @@ jobs:
ffversion: ${{ steps.ffversion.outputs.ffversion }}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: uname -a
run: uname -a
@@ -39,28 +43,28 @@ 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 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
run: sudo apt-get update && sudo apt-get install -y gcc-13 jq 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 libefl-all-dev libunwind-dev liblua5.4-dev libvdpau-dev libva-dev rpm ninja-build
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa quickjs-ng --ignore-dependencies
- name: Initialize CodeQL
if: inputs.arch == 'amd64'
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
with:
languages: c
- name: configure project
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: CC=gcc-13 CMAKE_PREFIX_PATH=/home/linuxbrew/.linuxbrew PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: perform CodeQL analysis
if: inputs.arch == 'amd64'
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
- name: list features
run: ./fastfetch --list-features
@@ -69,7 +73,29 @@ jobs:
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
run: |
{ time -p ./fastfetch -c presets/ci.jsonc --format json > fastfetch.raw.json 2> fastfetch.error; } 2> fastfetch.time
sed -n '/^[[:space:]]*\[/,$p' fastfetch.raw.json > fastfetch.json
cat fastfetch.json
cat fastfetch.error >&2
cat fastfetch.time >&2
- name: prepare benchmark data
run: |
real_seconds=$(awk '$1 == "real" { print $2 }' fastfetch.time)
jq -e 'type == "array"' fastfetch.json > /dev/null
jq --arg platform "linux" --arg arch "${{ inputs.arch }}" --argjson real_seconds "$real_seconds" '
map(select(.stat | type == "number") | {
name: ("fastfetch " + $platform + " " + $arch + " module " + .type),
unit: "ms",
value: .stat
}) + [{
name: ("fastfetch " + $platform + " " + $arch + " total process time"),
unit: "ms",
value: ($real_seconds * 1000)
}]
' fastfetch.json > benchmark.json
cat benchmark.json
- name: run flashfetch
run: time ./flashfetch
@@ -97,7 +123,13 @@ jobs:
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-linux-${{ inputs.arch }}
path: ./fastfetch-*.*
- name: upload benchmark data
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: benchmark-linux-${{ inputs.arch }}
path: benchmark.json
+8 -5
View File
@@ -3,6 +3,9 @@ name: Reusable Linux i686
on:
workflow_call:
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -11,7 +14,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: uname -a
run: uname -a
@@ -26,18 +29,18 @@ 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 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libefl-all-dev libunwind-dev liblua5.4-dev libvdpau-dev libva-dev rpm ninja-build
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa quickjs-ng --ignore-dependencies
- name: cmake version
run: cmake --version
- name: configure project
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
run: CC=gcc-13 CMAKE_PREFIX_PATH=/home/linuxbrew/.linuxbrew PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_VERSION=5.10.0 -DCMAKE_SYSTEM_PROCESSOR=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -64,7 +67,7 @@ jobs:
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-linux-i686
path: ./fastfetch-*.*
+60
View File
@@ -0,0 +1,60 @@
name: Reusable Linux loong64
on:
workflow_call:
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: set up QEMU for loong64
uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0
- name: build in loong64 container
run: |
docker run --rm --platform linux/loong64 \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
lcr.loongnix.cn/debian:14 \
bash -c '
set -e
uname -a
cat /etc/os-release || true
apt-get update
apt-get install -y --no-install-recommends \
cmake make gcc g++ \
libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev \
libdconf-dev libdbus-1-dev libmagickcore-dev \
libsqlite3-dev librpm-dev \
libegl-dev libglx-dev ocl-icd-opencl-dev \
libpulse-dev libdrm-dev \
libelf-dev libefl-all-dev \
liblua5.4-dev \
libvdpau-dev libva-dev \
rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j$(nproc)
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
'
- name: upload artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-linux-loong64
path: ./fastfetch-*.*
+7 -4
View File
@@ -7,6 +7,9 @@ on:
required: true
type: string
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -15,10 +18,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: uraimo/run-on-arch-action@v3
uses: uraimo/run-on-arch-action@460cb8e6d9f726a588fc9b5e681c8a6cab09ae41 # v3.2.0
id: runcmd
with:
arch: ${{ inputs.arch }}
@@ -28,7 +31,7 @@ jobs:
uname -a
apt-get update && apt-get install -y software-properties-common
add-apt-repository -y ppa:ubuntu-toolchain-r/test
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev libefl-all-dev liblua5.4-dev libvdpau-dev libva-dev rpm
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -39,7 +42,7 @@ jobs:
ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-linux-${{ inputs.arch }}
path: ./fastfetch-*.*
+56 -7
View File
@@ -10,6 +10,9 @@ on:
required: true
type: string
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -18,17 +21,35 @@ jobs:
runs-on: ${{ inputs.runs-on }}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: uname -a
run: uname -a
- name: install required packages
- name: install required packages with MacPorts # Homebrew dropped Intel support
if: inputs.arch == 'amd64'
run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
curl -fsSL https://github.com/macports/macports-base/releases/download/v2.12.6/MacPorts-2.12.6-15-Sequoia.pkg -o "$RUNNER_TEMP/MacPorts.pkg"
sudo installer -pkg "$RUNNER_TEMP/MacPorts.pkg" -target /
echo /opt/local/bin >> "$GITHUB_PATH"
echo /opt/local/sbin >> "$GITHUB_PATH"
export PATH=/opt/local/bin:/opt/local/sbin:$PATH
sudo port selfupdate
sudo port install vulkan-loader vulkan-headers MoltenVK ImageMagick7 chafa lua quickjs-ng jq
- name: install required packages with Homebrew
if: inputs.arch == 'aarch64'
run: |
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew update
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa lua quickjs-ng jq
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
run: |
if [ "${{ inputs.arch }}" = "amd64" ]; then
export CMAKE_PREFIX_PATH=/opt/local
export PKG_CONFIG_PATH=/opt/local/lib/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}
fi
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --target package --verbose -j4
@@ -37,10 +58,32 @@ jobs:
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan --stat false
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan:bluetooth:bluetoothradio --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan --format json
run: |
{ time -p ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan:bluetooth:bluetoothradio --format json > fastfetch.raw.json 2> fastfetch.error; } 2> fastfetch.time
sed -n '/^[[:space:]]*\[/,$p' fastfetch.raw.json > fastfetch.json
cat fastfetch.json
cat fastfetch.error >&2
cat fastfetch.time >&2
- name: prepare benchmark data
run: |
real_seconds=$(awk '$1 == "real" { print $2 }' fastfetch.time)
jq -e 'type == "array"' fastfetch.json > /dev/null
jq --arg platform "macos" --arg arch "${{ inputs.arch }}" --argjson real_seconds "$real_seconds" '
map(select(.stat | type == "number") | {
name: ("fastfetch " + $platform + " " + $arch + " module " + .type),
unit: "ms",
value: .stat
}) + [{
name: ("fastfetch " + $platform + " " + $arch + " total process time"),
unit: "ms",
value: ($real_seconds * 1000)
}]
' fastfetch.json > benchmark.json
cat benchmark.json
- name: run flashfetch
run: time ./flashfetch
@@ -52,7 +95,13 @@ jobs:
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-macos-${{ inputs.arch }}
path: ./fastfetch-*.*
- name: upload benchmark data
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: benchmark-macos-${{ inputs.arch }}
path: benchmark.json
+9 -4
View File
@@ -3,6 +3,9 @@ name: Reusable Musl amd64
on:
workflow_call:
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -10,16 +13,18 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: setup alpine linux
uses: jirutka/setup-alpine@master
uses: jirutka/setup-alpine@ae3b3ddba35054804fc4a3507b519fa7e8152050 # v1.4.1
with:
branch: edge
- name: install dependencies
run: |
cat /etc/alpine-release
uname -a
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev lua5.4-dev quickjs-ng-dev libvdpau-dev libva-dev gcc g++
shell: alpine.sh --root {0}
- name: build
@@ -39,7 +44,7 @@ jobs:
shell: alpine.sh {0}
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-musl-amd64
path: ./fastfetch-*.*
+45 -21
View File
@@ -3,39 +3,63 @@ name: Reusable NetBSD amd64
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
shell: cpa.sh {0}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: cross-platform-actions/action@master
- name: Start VM
uses: cross-platform-actions/action@faa0c6197e94aacf1c5956460152c8380d3560a5 # v1.5.0
with:
operating_system: netbsd
architecture: x86-64
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
CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
shell: bash
cpu_count: 4
- name: Show system info
run: |
uname -a
pkgin -v
- name: Update and install dependencies
run: |
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick libva libvdpau
- name: CMake configuration
run: CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_BUILD_TYPE=${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }} .
- name: CMake build
run: cmake --build . --target package --verbose -j4
- name: List features
run: ./fastfetch --list-features
- name: Run normal
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: Run json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: Run flashfetch
run: time ./flashfetch
- name: Run ldd
run: ldd fastfetch
- name: Run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-netbsd-amd64
path: ./fastfetch-*.*
+5 -2
View File
@@ -3,6 +3,9 @@ name: Reusable No Features Test
on:
workflow_call:
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -12,13 +15,13 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: uname -a
run: uname -a
- name: configure project
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_THREADS=OFF
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_EET=OFF -DENABLE_THREADS=OFF
- name: build project
run: cmake --build . --target package --verbose -j4
+51 -23
View File
@@ -3,40 +3,68 @@ name: Reusable OmniOS amd64
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
shell: cpa.sh {0}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: vmactions/omnios-vm@v1
- name: Start VM
uses: cross-platform-actions/action@faa0c6197e94aacf1c5956460152c8380d3560a5 # v1.5.0
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 ninja
operating_system: omnios
version: 'r151058'
shell: bash
cpu_count: 4
run: |
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-omnios-amd64")' >> CPackConfig.cmake
cpack -V
- name: Show system info
run: |
uname -a
- name: Update and install dependencies
run: |
sudo pkg update --accept || true
sudo pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja
- name: CMake configuration
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_BUILD_TYPE=${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }} .
- name: CMake build
run: cmake --build . --verbose -j4
- name: List features
run: ./fastfetch --list-features
- name: Run normal
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: Run json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: Run flashfetch
run: time ./flashfetch
- name: Run ldd
run: ldd fastfetch
- name: Run tests
run: ctest --output-on-failure
- name: Package
run: |
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-omnios-amd64")' >> CPackConfig.cmake
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-omnios-amd64
path: ./fastfetch-*.*
+45 -22
View File
@@ -3,40 +3,63 @@ name: Reusable OpenBSD amd64
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
shell: cpa.sh {0}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: cross-platform-actions/action@master
- name: Start VM
uses: cross-platform-actions/action@faa0c6197e94aacf1c5956460152c8380d3560a5 # v1.5.0
with:
operating_system: openbsd
architecture: x86-64
cpu_count: 4
version: '7.9'
shell: bash
version: '7.8'
environment_variables: 'CMAKE_BUILD_TYPE'
run: |
uname -a
sudo pkg_add -u
sudo pkg_add -r llvm-21.1.2p0 cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
CC=clang-21 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
cpu_count: 4
- name: Show system info
run: |
uname -a
- name: Update and install dependencies
run: |
sudo pkg_add -u
sudo pkg_add -r llvm-21.1.8p4 cmake git wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa lua-5.4.8p0 # pkg-config is preinstalled
- name: CMake configuration
run: CC=clang-21 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_BUILD_TYPE=${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }} .
- name: CMake build
run: cmake --build . --target package --verbose -j4
- name: List features
run: ./fastfetch --list-features
- name: Run normal
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: Run json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: Run flashfetch
run: time ./flashfetch
- name: Run ldd
run: ldd fastfetch
- name: Run tests
run: ctest --output-on-failure
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-openbsd-amd64
path: ./fastfetch-*.*
+7 -4
View File
@@ -7,23 +7,26 @@ on:
required: true
type: string
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: get latest release version
id: get_version_release
uses: pozetroninc/github-action-get-latest-release@master
uses: pozetroninc/github-action-get-latest-release@2a61c339ea7ef0a336d1daa35ef0cb1418e7676c # v0.8.0
with:
repository: ${{ github.repository }}
- name: download artifacts
if: inputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v8
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- name: create release
if: inputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
uses: ncipollo/release-action@339a81892b84b4eeb0f6e744e4574d79d0d9b8dd # v1.21.0
with:
tag: ${{ inputs.ffversion }}
commit: ${{ github.sha }}
@@ -50,7 +53,7 @@ jobs:
- name: update release body
if: inputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
uses: ncipollo/release-action@339a81892b84b4eeb0f6e744e4574d79d0d9b8dd # v1.21.0
with:
tag: ${{ inputs.ffversion }}
commit: ${{ github.sha }}
+7 -4
View File
@@ -3,6 +3,9 @@ name: Reusable Solaris amd64
on:
workflow_call:
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -11,17 +14,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: vmactions/solaris-vm@v1
uses: vmactions/solaris-vm@315163f088b66e55bbcc45928bd224d4973b2312 # v1.3.8
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
pkg install cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja dconf mesa lua
run: |
export PKG_CONFIG_PATH=/usr/lib/64/pkgconfig
@@ -37,7 +40,7 @@ jobs:
cpack -V
- name: upload artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-solaris-amd64
path: ./fastfetch-*.*
+5 -5
View File
@@ -3,8 +3,8 @@ name: Reusable Spellcheck
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
permissions:
contents: read
jobs:
spellcheck:
@@ -12,13 +12,13 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install codespell
shell: bash
run: |
sudo apt-get update || true
sudo apt-get install -y codespell
pip3 install codespell
codespell --version
- name: Run Spellchecker
run: codespell
+48 -8
View File
@@ -18,6 +18,18 @@ on:
msys-arch:
required: true
type: string
secrets:
SIGNPATH_API_TOKEN:
description: SignPath REST API token used to submit the signing request
# Optional so that runs without the secret (pull requests, forks)
# still work; the signing step is skipped there anyway.
required: false
permissions:
contents: read
# The SignPath action reads job details and downloads the unsigned
# artifact with the workflow token.
actions: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -30,14 +42,14 @@ jobs:
shell: msys2 {0}
steps:
- name: checkout repository
uses: actions/checkout@v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: setup-msys2
uses: msys2/setup-msys2@v2
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0
with:
msystem: ${{ inputs.msystem }}
update: true
install: git mingw-w64-clang-${{ inputs.msys-arch }}-7zip mingw-w64-clang-${{ inputs.msys-arch }}-cmake mingw-w64-clang-${{ inputs.msys-arch }}-clang mingw-w64-clang-${{ inputs.msys-arch }}-vulkan-loader mingw-w64-clang-${{ inputs.msys-arch }}-vulkan-headers mingw-w64-clang-${{ inputs.msys-arch }}-opencl-icd mingw-w64-clang-${{ inputs.msys-arch }}-opencl-headers mingw-w64-clang-${{ inputs.msys-arch }}-cppwinrt mingw-w64-clang-${{ inputs.msys-arch }}-imagemagick mingw-w64-clang-${{ inputs.msys-arch }}-chafa mingw-w64-clang-${{ inputs.msys-arch }}-directx-headers
install: git mingw-w64-clang-${{ inputs.msys-arch }}-7zip mingw-w64-clang-${{ inputs.msys-arch }}-cmake mingw-w64-clang-${{ inputs.msys-arch }}-clang mingw-w64-clang-${{ inputs.msys-arch }}-jq mingw-w64-clang-${{ inputs.msys-arch }}-vulkan-loader mingw-w64-clang-${{ inputs.msys-arch }}-vulkan-headers mingw-w64-clang-${{ inputs.msys-arch }}-opencl-icd mingw-w64-clang-${{ inputs.msys-arch }}-opencl-headers mingw-w64-clang-${{ inputs.msys-arch }}-cppwinrt mingw-w64-clang-${{ inputs.msys-arch }}-imagemagick mingw-w64-clang-${{ inputs.msys-arch }}-chafa mingw-w64-clang-${{ inputs.msys-arch }}-lua mingw-w64-clang-${{ inputs.msys-arch }}-quickjs-ng mingw-w64-clang-${{ inputs.msys-arch }}-directx-headers
- name: print msys version
run: uname -a
@@ -49,7 +61,7 @@ jobs:
run: cmake --build . --verbose -j4
- name: copy necessary dlls
run: cp /${{ inputs.msystem-lower }}/bin/{OpenCL,vulkan-1}.dll .
run: cp /${{ inputs.msystem-lower }}/bin/{lua55,libqjs-0}.dll .
- name: list features
run: ./fastfetch --list-features
@@ -58,7 +70,29 @@ jobs:
run: time ./fastfetch -c presets/ci.jsonc --stat false
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
run: |
{ time -p ./fastfetch -c presets/ci.jsonc --format json > fastfetch.raw.json 2> fastfetch.error; } 2> fastfetch.time
sed -n '/^[[:space:]]*\[/,$p' fastfetch.raw.json > fastfetch.json
cat fastfetch.json
cat fastfetch.error >&2
cat fastfetch.time >&2
- name: prepare benchmark data
run: |
real_seconds=$(awk '$1 == "real" { print $2 }' fastfetch.time)
jq -e 'type == "array"' fastfetch.json > /dev/null
jq --arg platform "windows" --arg arch "${{ inputs.arch }}" --argjson real_seconds "$real_seconds" '
map(select(.stat | type == "number") | {
name: ("fastfetch " + $platform + " " + $arch + " module " + .type),
unit: "ms",
value: .stat
}) + [{
name: ("fastfetch " + $platform + " " + $arch + " total process time"),
unit: "ms",
value: ($real_seconds * 1000)
}]
' fastfetch.json > benchmark.json
cat benchmark.json
- name: run flashfetch
run: time ./flashfetch
@@ -72,7 +106,7 @@ jobs:
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
id: upload-unsigned-artifact
name: upload artifacts for signing
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-windows-${{ inputs.arch }}
path: |
@@ -82,7 +116,7 @@ jobs:
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
name: submit signing request
uses: signpath/github-action-submit-signing-request@v1
uses: signpath/github-action-submit-signing-request@c92b958760219087e01f8d67a1669ed57afe2627 # v2.3
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
@@ -99,8 +133,14 @@ jobs:
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ inputs.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
- name: upload true artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: fastfetch-windows-${{ inputs.arch }}
path: ./fastfetch-windows-${{ inputs.arch }}.*
overwrite: true
- name: upload benchmark data
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: benchmark-windows-${{ inputs.arch }}
path: benchmark.json
+44 -33
View File
@@ -6,17 +6,19 @@ on:
jobs:
spellcheck:
permissions:
contents: read
uses: ./.github/workflows/build-spellcheck.yml
no-features-test:
needs: spellcheck
name: No-features-test
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-no-features-test.yml
secrets: inherit
linux-hosts:
needs: no-features-test
name: Linux-${{ matrix.arch }}
permissions:
security-events: write
@@ -32,36 +34,32 @@ jobs:
with:
arch: ${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
secrets: inherit
linux-i686:
needs: no-features-test
name: Linux-i686
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-linux-i686.yml
secrets: inherit
linux-armv7l:
needs: no-features-test
name: Linux-armv7l
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-linux-armv7l.yml
secrets: inherit
linux-armv6l:
name: Linux-armv6l
linux-loong64:
needs: no-features-test
name: Linux-loong64
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-linux-armv6l.yml
secrets: inherit
uses: ./.github/workflows/build-linux-loong64.yml
linux-vms:
needs: no-features-test
name: Linux-${{ matrix.arch }}
permissions:
security-events: write
contents: read
strategy:
matrix:
@@ -72,17 +70,18 @@ jobs:
uses: ./.github/workflows/build-linux-vms.yml
with:
arch: ${{ matrix.arch }}
secrets: inherit
musl-amd64:
needs: no-features-test
name: Musl-amd64
permissions:
contents: read
uses: ./.github/workflows/build-musl-amd64.yml
secrets: inherit
macos-hosts:
needs: no-features-test
name: macOS-${{ matrix.arch }}
permissions:
security-events: write
contents: read
strategy:
matrix:
@@ -95,63 +94,64 @@ jobs:
with:
arch: ${{ matrix.arch }}
runs-on: ${{ matrix.runs-on }}
secrets: inherit
omnios-amd64:
needs: no-features-test
name: OmniOS-amd64
permissions:
contents: read
uses: ./.github/workflows/build-omnios-amd64.yml
secrets: inherit
solaris-amd64:
needs: no-features-test
name: Solaris-amd64
permissions:
contents: read
uses: ./.github/workflows/build-solaris-amd64.yml
secrets: inherit
freebsd-amd64:
needs: no-features-test
name: FreeBSD-amd64
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-freebsd-amd64.yml
secrets: inherit
openbsd-amd64:
needs: no-features-test
name: OpenBSD-amd64
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-openbsd-amd64.yml
secrets: inherit
netbsd-amd64:
needs: no-features-test
name: NetBSD-amd64
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-netbsd-amd64.yml
secrets: inherit
dragonfly-amd64:
needs: no-features-test
name: DragonFly-amd64
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-dragonfly-amd64.yml
secrets: inherit
haiku-amd64:
needs: no-features-test
name: Haiku-amd64
permissions:
security-events: write
contents: read
uses: ./.github/workflows/build-haiku-amd64.yml
secrets: inherit
windows-hosts:
needs: no-features-test
name: Windows-${{ matrix.arch }}
permissions:
security-events: write
contents: read
# The SignPath action reads job details and downloads the unsigned
# artifact with the workflow token.
actions: read
strategy:
matrix:
include:
@@ -172,7 +172,19 @@ jobs:
msystem: ${{ matrix.msystem }}
msystem-lower: ${{ matrix.msystem-lower }}
msys-arch: ${{ matrix.msys-arch }}
secrets: inherit
secrets:
SIGNPATH_API_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN }}
benchmark:
if: github.event_name == 'push' && github.ref == 'refs/heads/dev' && github.repository == 'fastfetch-cli/fastfetch'
name: Benchmark
needs:
- linux-hosts
- macos-hosts
- windows-hosts
permissions:
contents: write
uses: ./.github/workflows/build-benchmark.yml
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
@@ -181,7 +193,7 @@ jobs:
- linux-hosts
- linux-i686
- linux-armv7l
- linux-armv6l
- linux-loong64
- linux-vms
- musl-amd64
- macos-hosts
@@ -198,4 +210,3 @@ jobs:
uses: ./.github/workflows/build-release.yml
with:
ffversion: ${{ needs.linux-hosts.outputs.ffversion }}
secrets: inherit
+10 -5
View File
@@ -1,8 +1,10 @@
build/
.vs/
.vscode/
.cache/
.kdev4/
/build/
/build_*/
/build-*/
/.vs/
/.vscode/
/.cache/
/.kdev4/
.DS_Store
cscope.*
tags
@@ -10,3 +12,6 @@ fastfetch.kdev4
*.user
*.user.*
*.swp
*.log
/*.zh.md
/.*-ai/
+327 -5
View File
@@ -1,7 +1,329 @@
# Unreleased
Features:
* Added CPU name and frequency detection support on SPARC. (CPU, Linux)
# 2.68.1
Changes:
* The DE / WM / LM modules now reports the full name "Desktop Environment" / "Window Manager" / "Login Manager" instead of the abbreviations.
Features:
* Improved Login Manager (LM) module
* Added support on macOS, Windows and POSIX systems without systemd (by process list enumeration).
* Reports pretty name on Linux.
* Added Top module to print processes with the highest CPU, memory or disk I/O usage. (Top)
* Added module key localization support. (General)
* Added a new option `--key-language <?lang>` (`display.key.language: "<?lang>"` in JSON config). When left empty, it defaults to the system locale.
* See `fastfetch -h key-language` for all supported languages.
* Exposed in custom key format as `{module-name}`.
* Improved Wi-Fi module
* Added Wifi channel width detection, exposed via `{channel-width}` in custom format (reports 0 when not supported).
* Improved Wifi channel frequency accuracy and fortified detection on Windows, macOS.
* Added Wifi detection support on SunOS, Haiku.
* Added Battery detection support on SunOS. (Battery, SunOS)
* Added terminal font size detection support on Termux. (TerminalFont, Android)
* Improved GTK theme/icons/font detection on standalone WMs such as Hyprland, sway, niri and i3. (Theme, Linux)
* Improved fish completion scripts to print enum descriptions. (Completion)
* Enabled Wayland support on Android. (DisplayServer, Android)
* Added DE detection support for ASUS Zenfone. (DE, Android)
* Added new ARM SoCs (CPU, Linux / Android)
Bugfixes:
* Fixed I/O rate calculation precision in DiskIO and NetIO, and prevented division by zero. (DiskIO / NetIO)
* Fixed the fast path of ash version detection. (Shell)
* Fixed memory usage detection support on x86-32 FreeBSD (Memory, FreeBSD)
* Note: Although 32-bit systems are still supported, they are deprecated and barely tested. Users are encouraged to upgrade to 64-bit systems.
* Some internal cleanups and optimizations.
* Attempted to fix potential issues on big-endian systems
* Not tested due to lack of access to big-endian hardware.
Logos:
* Added macOS_old
* Added Omarchy, Omarchy2
# 2.67.1
Bugfixes:
* Fixed a `Symbol not found` error when running on macOS 10.15. (#2499, Codec, macOS)
* Fixed Alacritty font size never being parsed from the TOML config. (#2501, TerminalFont)
* Fixed bright colors incorrectly being active when the terminal uses a light theme. (#2509, Display)
* Fixed Ghostty terminal font detection (TerminalFont)
* Now tries to load the config with the `.ghostty` extension. (#2500)
* Fixed `font-family` fallback order. (#2510)
* Some internal cleanups and optimizations.
Features:
* Added a C23 compiler check so the build process gracefully exits during CMake configuration if the compiler is unsupported. (CMake)
* Added compatibility workarounds for Apple Clang 16 to fix building on macOS 14. (CMake, macOS)
* Reported real Android version codenames (e.g., "Baklava", "Vanilla Ice Cream") instead of "REL". (OS, Android)
* Added Loadavg detection support on Haiku R1B6. (Loadavg, Haiku)
* Enabled image logo support in the Zellij terminal multiplexer. (#2507, Logo)
* Improved Locale detection on Windows (Locale, Windows)
* Now respects `LC_ALL` and `LANG` environment variables if set for better compatibility with MSYS2/cygwin.
* Appends the active system Code Page (e.g., `.UTF-8` or `.Windows-1252`) to the default system locale fallback.
# 2.67.0
Changes:
* The minimum supported compiler version has been raised to GCC 13 (released on 2023-04-26) and Clang 16 (released on 2023-03-17) to accommodate the new C23 syntax used throughout the codebase. (General)
* As a result, building from source in Debian 12 (which only ships GCC 12 by default) is no longer supported. Users must upgrade their compiler or use the prebuilt binaries from the GitHub releases page.
* The `general.preRun` option has been removed due to security concerns. (General)
* Users who relied on this option to run a command before printing output will need to move that logic to an external wrapper.
* The `{status}` placeholder in Battery custom format is now an array type instead of a single comma-separated string. (Battery)
* This is a breaking change for users who print `{status}` in Lua scripts. They can use `table.concat(...)` to join the array into a single string if needed.
* The `--gen-config-*` flags (`--gen-config-full`, `--gen-config-force`, `--gen-config-full-force`) have been removed and their functions have been merged into `--gen-config`. (Global)
* See features below.
Features:
* `--gen-config` now opens an interactive configuration TUI to make generating config files easier.
* It falls back to non-interactive generation when `$NO_COLOR` is set or when stdin/stdout is not a TTY. This behavior can also be used to disable the interactive mode.
* Added an experimental [WebUI](https://fastfetch-cli.github.io/fastfetch-config/) ([separate project](https://github.com/fastfetch-cli/fastfetch-config)) for generating and editing configs.
* Added `-w`/`--watch` as a seconds-based alias for `--dynamic-interval`, defaulting to 1 second when no value is provided. (#2478, Watch)
* Added InitSystem detection on Windows, reporting the first userland process (`smss.exe`). (InitSystem, Windows)
* Added CPU and GPU temperature detection support for Apple M5 series chips. (CPU / GPU, macOS)
* Reported `Basic` as the Windows theme when DWM is disabled. (Theme, Windows)
* Improved Ghostty terminal font detection performance. (#2122, TerminalFont)
* It now parses Ghostty directly instead of running `ghostty +show-config`.
* Added support for a wider range of TOML config syntaxes used by Alacritty. (#2456, TerminalFont)
Bugfixes:
* Fixed a potential fish version detection error. (Shell, Linux)
* Fixed incorrect resolution reporting when a monitor advertises multiple preferred modes. (#2481, Display, Linux)
* Fixed connected monitors being missed when Wayland output events arrive late. (#2451, Display, Linux)
* Fixed VP9 codec detection on macOS. (Codec, macOS)
* Corrected Base64 encoding on big-endian hosts. (#2470)
* Fixed invalid URL parsing in the PublicIP module. (PublicIP)
* Correctly reported virtual GPUs on Windows. (#2461, GPU, Windows)
* Added a size limit for network responses to prevent excessive memory usage and mitigate potential attacks. (PublicIP / Weather)
* Fixed Ubuntu Studio Core detection. (OS, Linux)
* Relaxed the HTTP response check so that both `HTTP/1.0` and `HTTP/1.1` responses are accepted when fetching data over the network. (PublicIP / Weather)
* Various internal cleanups and optimizations:
* Fixed multiple memory leaks (Separator, Camera, Codec, Display).
* Added integer overflow checks to the string buffer implementation.
* Various code cleanups and compiler warning fixes.
Logos:
* Removed Hypros, MagpieOS, Furreto, EmperorOS and Magix
# 2.66.0
Changes:
* CPU package count is no longer reported in the default output.
* Users can still print it in custom formats via `{packages}`
Bugfixes:
* Fixed compatibility with WSL 2.9.3 (#2433, WM, Linux)
* Fixed AMD GPU names not being queried accurately in `driverSpecific` mode (GPU, Linux)
* Fixed GPU core counting for Apple Silicon GPU on Asahi Linux (GPU, Linux)
* Some internal cleanups and optimizations.
Features:
* Added Astra Linux version detection (OS, Linux)
* Improved performance of Windows PowerShell version detection (Shell, Windows)
* Improved performance of Media module on macOS (Media, macOS)
* Added proxmox backup server detection (#2443, OS, Linux)
Logos:
* Added Flatcar, Azure Linux
* Added Chimera_small, Chimera2, Parabola2_small, PostmarketOS2, Qubes_small
* Updated linuxmint_small
* Cleaned up distro names
# 2.65.2
Changes:
* Memory usage calculations now exclude the ZFS ARC cache on Linux, FreeBSD, NetBSD, and SunOS. (#1995 / #2418, Memory)
* This prevents the Memory module from reporting artificially high memory usage on systems with the ZFS kmod enabled.
Bugfixes:
* The GPU module no longer pings sleeping dedicated GPUs on dual-GPU laptops. (#2419, GPU)
* As a result, PCIe link speed detection (introduced in v2.65.0) is now only enabled in `driverSpecific` mode.
* Fixed a crash when detecting hardware codec support with the `amdgpu` driver on Linux. (#2419, Codec, Linux)
Logos:
* Updated CachyOS_small; fixed CachyOS logo colors to match the official logo better
* Added Turkish
# 2.65.1
No changes
# 2.65.0
Changes:
* `display.disableLinewrap` now defaults to `false`.
* This allows long lines to wrap instead of being truncated, preventing confusion for new users.
* Wrapped lines may overlap with the image logo. Users who prefer the old behavior can set `display.disableLinewrap: true` in their config file or use `--disable-linewrap true` on the command line.
* Reorders package manager variables in custom format strings, moving aggregate variables (e.g., `all`, `brew-all`, `flatpak-all`) to the end. (Packages)
* This is a breaking change for users relying on numeric placeholders (e.g., `{1}`). Numeric placeholders are a long-deprecated feature; named placeholders (e.g., `{pacman}`) are always preferred and future-proof.
* Enables `showPeCoreCount` by default to better display hybrid-architecture core counts. (CPU)
* No longer accepts `chafa` options in config files if `chafa` support was disabled at compile time. (Logo)
* This may affect users who generated their config files using `fastfetch --gen-full-config`. To resolve this, simply remove the `chafa` section from the config file.
Features:
* Adds detection for CPU code names (e.g., "Alder Lake", "Zen 4") and manufacturing technologies (e.g., "Intel 7", "TSMC N4") on x86 processors. (#1501, CPU, X86)
* These can be used in custom formats via `{code-name}` and `{technology}`.
* Adds PCIe link speed detection (current and max generation & lanes) for GPUs on Linux and Windows.
* These can be used in custom formats via `{pcie-max-speed}` and `{pcie-curr-speed}`.
* Adds HDR display detection via the `wp-color-management-v1` Wayland protocol. (#2356, Display, Linux)
* Previously, HDR detection was only supported on KDE Plasma.
* Adds the `egl-ext` detection method, which uses `EGL_EXT_device_enumeration` for GPU enumeration. (GPU)
* Adds terminal version and font detection for `kmscon`. (#2393, Terminal / TerminalFont, Linux)
* Adds the currently-in-beta code name "Golden Gate" for macOS 27. (OS, macOS)
* Adds WPA version detection on FreeBSD. (Wifi, FreeBSD)
* Adds package manager support for `porg` (#2405) and `install-release` (#2342). (Packages, Linux)
* Adds Weston version detection. (WM, Linux)
* Improves the core type (P-Core/E-Core) fetching mechanism on Windows by using `EfficiencyClass` instead of legacy frequency inference. (CPU, Windows)
* Improves display detection compatibility with KDE 6.7. (Display, Linux)
* Improves display serial number detection, now preferring alphanumeric serial numbers when available. (Display)
* This can be used in custom formats via `{serial}`.
* Improves the performance of `emerge` package manager detection. (#2406, Packages, Linux)
* Improves error messages for config file parsing errors.
* Improves reliability of the `Codec` module on Linux (Codec, Linux)
* Adds `va-x11` backend for VA-API and VDPAU, which is used if `va-drm` backend fails to initialize.
* Fixes an issue where the Codec module incorrectly reports no results when the `codec.showType` option is set.
Bugfixes:
* Fixes physical core detection on non-x86 architectures and simplifies the frequency detection code. (CPU, Linux)
* Fixes console mode and output code page initialization issues when running `fastfetch` in `Conhost`. (#2383, Windows)
* Fixes public IP detection randomly failing on Linux. (#2401, PublicIP, Linux)
* Fixes several memory leaks.
Logos:
* Adds Zerene OS. (#2404)
# 2.64.2
Bugfixes:
* Fixes image rendering being wiped quickly (#2374)
* Regression from v2.64.0
* Fixes ASCII logo being overwritten in `--dynamic-interval` mode
* Regression from v2.64.0
Logos:
* Updates OpenWrt and adds a small variant (#2376)
* The old one is renamed to `openwrt_old`
# 2.64.1
Features:
* Adds a CMake option `-DPACKAGES_REMOVE_DISABLED` to remove detection code of disabled packages (`-DPACKAGES_DISABLE_<PACKAGE_NAME>`) for slightly smaller binary size (Packages)
Bugfixes:
* Fixes compatibility issues with Lua 5.3
* Avoid possible infinite recursion in `encode_json` when encoding deeply nested tables or circular references
* Fixes compilation issues when building with old macOS SDKs
# 2.64.0
New **optional build** dependencies:
* [`libva`](https://github.com/intel/libva) and [`libvdpau`](https://www.freedesktop.org/wiki/Software/VDPAU) for the new `Codec` module.
* [Lua 5.3 to 5.5](https://www.lua.org/) for Lua scripting support, or [QuickJS](https://github.com/quickjs-ng/quickjs) v0.15.0 or newer for JavaScript scripting support.
Features:
* Adds `Codec` module support for Windows, macOS, Linux, and Android for hardware-accelerated video codec detection (Codec)
* Backends used (results may vary depending on the backend due to driver differences):
* Linux and BSD: VA-API (default) and VDPAU (fallback for NVIDIA). Fastfetch must be built with `libva` and `libvdpau` support to enable these backends.
* Windows: D3D12VA (Windows 11) and D3D11VA+MFT (Windows 10 or older)
* macOS: VideoToolbox
* Android: AMediaCodec
* Common: Vulkan Video (disabled by default; can be enabled with `"useVulkan": true`)
* By default, both encoders and decoders are reported. If no codecs are detected for a given type, `None` is reported. This behavior can be configured using the `"showType": "encoder|decoder"` option.
* Adds experimental Lua script support for custom formats (Global)
* Basic usage (using `Title` as an example): `{ "type": "title", "format": "lua:return string.format('Hello %s@%s', (...).userName, (...).hostName)" }`. The `lua:` prefix indicates a Lua script. A `return` statement is required to pass the final result back to the fastfetch module; otherwise, `nil` is returned implicitly and the entire module output is skipped.
* Parameters are passed via variable arguments `(...)`. Users can assign them to named variables for better readability. For example: `lua:local args = ...; string.format('Hello %s@%s', args.userName, args.hostName)`.
* The Lua interpreter instance is shared across all modules. This allows users to store and manipulate data across modules. For example:
* `{ "type": "shell", "format": "lua:shell = ..." } // Note: no "return" here`
* `{ "type": "terminal", "format": "lua:return shell.prettyName .. ' in ' .. (...).prettyName" } // This will print the detected shell and terminal names`
* A `json_encode(table, is_pretty)` function has been added to the Lua API for easier debugging. For example, `lua:return json_encode(...)` will print all available variables and their values in JSON format.
* Supported Lua versions: Lua 5.3 to 5.5 (Lua 5.1 and LuaJIT are not supported). The Lua version is auto-detected at build time. Once built, users can check the configured Lua version using `fastfetch --list-features`.
* Adds experimental QuickJS script support for custom formats as an alternative to Lua (Global)
* Basic usage: `{ "type": "title", "format": "qjs:`Hello ${this.userName}@${this.hostName}`" }`. The `qjs:` prefix indicates a JavaScript script. No `return` statement is needed; the final result is simply the evaluated value of the script.
* Parameters are passed via the `this` object. Usage is mostly the same as Lua, but using JavaScript syntax.
* Requires [quickjs-ng v0.15.0](https://github.com/quickjs-ng/quickjs/releases/tag/v0.15.0) or newer.
* Adds CMake options `-DMODULE_DISABLE_<MODULE_NAME>=ON` to disable modules at compile time for a smaller binary size
* Use `cmake -L . | grep MODULE_DISABLE_` to list all available options.
* These options rely on LTO for dead code elimination (`-DCMAKE_BUILD_TYPE=Release` should enable LTO by default).
* Adds the ability to remove unneeded ASCII logos without modifying the fastfetch source code, further reducing binary size
* Simply remove the corresponding logo file from the logo directory (`src/logo/ascii/[a-z]/*`) and re-run `cmake`.
* Improves string manipulation specifiers in custom formats
* They are now ANSI escape-aware and work correctly with colored output (e.g., percentages with `num-color`) (#2364). Limitations:
* They are still not wide-character aware and treat CJK and emoji characters as raw bytes.
* Escape sequences in the middle of strings are not supported.
* A new `|` specifier has been added to center strings. For example, `{user-name|20}` will center the username in a 20-character-wide field.
* Adds preliminary `Bootmgr`, `Brightness`, and `WMTheme` detection support for Haiku (#2358, Haiku)
* Adds `Wallpaper` and `WMTheme` detection support for the COSMIC desktop environment (Linux)
* Improves terminal name detection for Nix packages (#2352, Terminal, Linux)
* Adds DDC/CI brightness detection support for FreeBSD (Brightness, FreeBSD)
* DDC/CI communication can be very slow. Users can set the `ddcciSleep: null` option to skip DDC/CI detection.
* Reworks the built-in logo printing logic. ASCII logos and modules are now printed line by line, avoiding issues like #2239
* Note: Image logos are not affected by this change and still print the entire image first before printing any modules.
* Adds a new `--logo-padding-bottom` option to control the padding between the bottom of the logo and the first module when `--logo-position top` is used
* Previously, `--logo-padding-right` was used for both right and bottom padding.
* Adds `Samsung Exynos 2600` to CPU detection (CPU, Android)
* Adds terminal font detection support for the Muxy terminal (TerminalFont, macOS)
* Improves the performance of BusyBox (ash) version detection and always reports `ash` as the pretty name (Shell, Linux)
Bugfixes:
* Fixes SwayFX version detection (WM, Linux)
* Fixes fallback font detection for Ghostty (TerminalFont, macOS)
* Fixes `--stat` output to correctly align with the right border (Global)
* Fixes boot manager on macOS 26 (mBoot) is incorrectly reported as `iBoot` (Bootmgr, macOS)
Logos:
* Adds Quasar (#2338, #2323), Origami, Origami_small (#2321, #2322), BerserkArch (#2324, #2310), and NixOS2 (#2346)
* Minor tweaks and color fixes for the NixOS_small logo (#2357)
* Updates NurOS (#2366)
# 2.63.1
Bugfixes:
* Fixes media length detection for Chrome on Linux (Media, Linux)
* Fixes segmentation fault when specifying unsupported modules on command line
* Disables usage of Netlink for Wi-Fi detection on s390x architectures (Wifi, Linux)
# 2.63.0
Changes:
* Introduces a new **build-only** dependency, `libefl`, for querying the Enlightenment window manager configuration:
* `libefl-all-dev` on Debian/Ubuntu
* `libefl-devel` on Fedora
* `efl` on Arch Linux
* The Windows-specific options `battery.useSetupApi` and `global.wmiTimeout` have been removed. (Windows)
Features:
* Adds wallpaper detection support on Haiku (#2314, Wallpaper, Haiku)
* Adds Wi-Fi 6 GHz channel detection and improves protocol reporting (Wifi, Linux)
* Improves Deepin version detection using `/etc/os-version` (#2300, OS, Linux)
* Adds Ubuntu Kylin and Ubuntu Unity flavor detection (OS, Linux)
* Adds NebiDE support (WMTheme, Linux)
* Adds package counting for `cards` on NuTyX (#2287, Packages, Linux)
* Adds `{am-pm}` to custom format for 12-hour time with am/pm (DateTime)
* Adds support for the Enlightenment desktop environment (#2165, WM, Linux)
* Adds support for playback progress detection (Media)
* The module now prints the current playback position and total media duration when supported by the player. If you prefer the previous behavior, you can set `media.percent.type: ["hide-others"]` to hide the new fields.
* Adds support for `global.playerName` for Windows (Media, Windows)
* This allows detecting a specified media player while ignoring others.
* Multi-battery detection is enabled on Windows by default (Battery, Windows)
Bugfixes:
* Improves DisplayServer compatibility on Linux by handling newer `kde-output-device-v2` protocol updates (DisplayServer, Linux)
* This fixes a long-standing issue where display detection fails with an `interface 'kde_output_device_mode_v2' has no event X` error.
* Improves Wi-Fi reliability on Linux by switching to a netlink implementation (Wifi, Linux)
* Improves network interface reliability and default route selection on macOS and Windows (Netif, macOS / Windows)
* Validates temperature color thresholds as integers when parsing JSON configs (Temps)
* Fixes TDE Konsole version detection (#2319, Terminal, Linux)
* Various internal cleanups and optimizations
Logos:
* Adds KibaOS, NebiOS, XJ380, openRuyi, Ximper
* Fixes GNOME OS built-in logo detection (#2296)
# 2.62.1
Bugfixes:
* Fixes Host module not working on some devices (#2279, Host, Linux)
* Fixes the Host module not working on some devices (#2279, Host, Linux)
* Regression from v2.61.0
Logos:
@@ -527,7 +849,7 @@ Features:
* Added support for interface speed detection on SunOS (LocalIP, SunOS)
* Added detection support for Xlibre (#1888, WM, Linux)
* Improved the accuracy of color detection (Cursor, macOS)
* Improved the proformance of `Nix` package manager detection on macOS by porting optimizations form Linux port (#1893, Packages, macOS)
* Improved the performance of `Nix` package manager detection on macOS by porting optimizations from the Linux port (#1893, Packages, macOS)
Bugfixes:
* Fixed custom object inheriting a key from the previous custom object if the key is blank (#1477)
@@ -1038,7 +1360,7 @@ Features:
* Change package manager name of NetBSD from `pkg` to `pkgsrc` (#1515, Packages, NetBSD)
* Detect SOC name on RISCV (#1519, CPU, Linux)
* Report marketing name of new QS8Es (CPU, Android)
* Acquire acquire more os info from lsb-release if missing from os-release (#1521)
* Acquire more OS info from lsb-release if missing from os-release (#1521)
* CMake: add option `-DCUSTOM_LSB_RELEASE_PATH` to specify the path of `lsb-release` file
* `-DCUSTOM_OS_RELEASE_PATH` has been supported since `v2.11.4`
* Report more SOC names on Android (CPU, Android)
@@ -1506,7 +1828,7 @@ Logos:
Bugfixes:
* Fix bad Intel Arc GPU name detection, which was supposed to be fixed in the last version but the change was reverted accidentally (#1177, GPU, Linux)
* Fix arm32 CPU name detection no longer work. Regression of 2.21.2 (CPU, Linux)
* Fix arm32 CPU name detection no longer working. Regression of 2.21.2 (CPU, Linux)
# 2.21.2
@@ -3001,7 +3323,7 @@ Features:
* Enhance `--percent-type` to allow hiding other texts (#387)
* Add Wifi module support for Linux
* Detect scaled resolutions (Windows, macOS)
* Optimise font module printing (Windows)
* Optimize font module printing (Windows)
* Detect pacman package count inside MSYS2 environment (Windows)
* Add Wifi / Battery module support for Android
* Disk name support for Linux
+356 -203
View File
File diff suppressed because it is too large Load Diff
+797
View File
@@ -0,0 +1,797 @@
# Contributing to fastfetch
<details>
<summary>
Disclaimer
</summary>
This document is generated by AI and reviewed by humans. It is primarily intended for AI-assisted development, while remaining useful to human developers.
</details>
Thank you for your interest in fastfetch. This document covers building, architecture, how to add a module or a logo, code style, commit conventions, and the pull request workflow.
fastfetch is a system information tool written in C23, supporting Linux, macOS, Windows, the BSDs, Solaris, Haiku and Android. The project places strong emphasis on **startup time** and on keeping **dependencies optional**; many design decisions only make sense under that constraint, and this document returns to it repeatedly.
---
## Table of contents
- [Contributor quick reference](#contributor-quick-reference)
- [Getting started](#getting-started)
- [Code map](#code-map)
- [Core architecture: modules vs. detection](#core-architecture-modules-vs-detection)
- [Module registration](#module-registration)
- [Walkthrough: adding a module](#walkthrough-adding-a-module)
- [Walkthrough: adding a logo](#walkthrough-adding-a-logo)
- [Platform conventions](#platform-conventions)
- [Code style](#code-style)
- [Commit messages](#commit-messages)
- [Changelog](#changelog)
- [Tests](#tests)
- [Pull requests](#pull-requests)
- [Pitfalls](#pitfalls)
---
## Contributor quick reference
| Task | Start here | Verify with |
|---|---|---|
| Build and run fastfetch | `run.sh`, `CMakeLists.txt` | `./run.sh` |
| Add a module | `src/modules/<name>/`, `src/detection/<name>/`, `src/modules/modules.c`, `CMakeLists.txt` | `cmake -B build && cmake --build build -j` |
| Add a platform implementation | `src/detection/<name>/<name>_<platform>.c`, the matching platform block in `CMakeLists.txt` | Build on the target platform or CI |
| Add an ASCII logo | `src/logo/ascii/<letter>/<name>.txt`, matching `<letter>.inc` | `./build/fastfetch --logo <name>` |
| Change formatting or JSON output | `src/modules/<name>/<name>.c` | `./build/fastfetch -s <name> --format json` |
| Change shared formatting or containers | `src/common/format.h`, `src/common/color.h`, `src/common/FFstrbuf.h` | Build and run the matching test |
| Run the test suite | `tests/`, `build/` | `cd build && ctest --output-on-failure` |
For a typical code change, the shortest useful iteration is: configure, build the `fastfetch` target, run the affected module, then run the tests. If you add a directory or a generated input, re-run `cmake -B build` so that CMake refreshes its file globs.
---
## Getting started
### Building
The quickest way is `run.sh` in the repository root: it creates `build/`, configures, compiles and runs the binary.
```sh
./run.sh # build and run
./run.sh --format json # arguments are forwarded to fastfetch
```
Manual build:
```sh
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build --target fastfetch -j$(nproc)
./build/fastfetch
```
The default build type is `RelWithDebInfo`. LTO is enabled whenever `ENABLE_LTO=ON` **and** `CMAKE_BUILD_TYPE != Debug`, so the default configuration enables it and only `Debug` builds omit it. This is significant because LTO here is not merely an optimization: it is what removes the code of disabled modules. See [Pitfalls](#pitfalls).
### Common build options
| Option | Default | Notes |
|---|---|---|
| `CMAKE_BUILD_TYPE` | `RelWithDebInfo` | LTO is on for anything but `Debug` |
| `BUILD_TESTS` | `OFF` | Builds the unit tests in `tests/` |
| `BUILD_FLASHFETCH` | `ON` | Also builds the stripped-down `flashfetch` |
| `BINARY_LINK_TYPE` | `dlopen` | `dlopen` / `dynamic` / `static` |
| `ENABLE_ASAN` | `OFF` | Address Sanitizer |
| `ENABLE_LTO` | `ON` | Link-time optimization |
| `MODULE_DISABLE_<NAME>` | `OFF` | Disable a module, e.g. `MODULE_DISABLE_GPU=ON` |
| `SET_TWEAK` | `ON` | Appends a tweak to the dev version; turned off for releases |
`BINARY_LINK_TYPE=dlopen` (the default) is a deliberate design choice: optional dependencies (Vulkan, Wayland, DBus, ImageMagick, chafa, …) are loaded at runtime, so a missing library never prevents startup. When adding a third-party dependency, use the dlopen helpers in `common/library.h` — do not link it directly.
For a minimal-dependency build, see `.github/workflows/build-no-features-test.yml`:
```sh
cmake -DBUILD_TESTS=On -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_X11=OFF \
-DENABLE_DBUS=OFF -DENABLE_ZLIB=OFF ... .
```
### Dependencies
Required: CMake ≥ 3.21 and a C23 compiler (GCC, Clang or MSVC). Everything else is optional.
Optional dependencies are auto-detected: libpci, libdrm, vulkan, wayland, xcb, xrandr, dbus, sqlite3, rpm, imagemagick{6,7}, chafa, zlib, egl, glx, opencl, freetype, pulse, ddcutil, elf, libzfs, and more.
---
## Code map
```
src/
├── fastfetch.c entry point: CLI parsing, module dispatch, main loop (36 KB)
├── flashfetch.c entry point for the stripped-down build
├── options/ global (non-module) config: general / display / logo
├── modules/ module layer — module formatting and output
├── detection/ detection layer — platform-specific data retrieval
├── common/ infrastructure: FFstrbuf, FFlist, formatting, printing, networking
├── logo/ 530 ASCII logos plus the image logo backends
└── 3rdparty/ yyjson, widecharwidth, display-library
```
Flow of control:
```
fastfetch.c → options/ (global configuration)
→ modules/ (76 modules, formatting and output)
→ detection/ (one platform implementation each, raw data)
→ common/ (infrastructure)
```
The number of module directories does not match the number of detection directories, which is expected. The following relationships are structural rather than a fixed inventory:
- **13 modules have no detection directory** — they are either pure layout (`break`, `separator`, `colors`, `title`, `logo`) or reuse another module's detection result (`display`, `monitor`, `kernel`, `shell`, `terminal`, `player`, `custom`, `datetime`).
- **4 detection directories serve modules with different names** — `displayserver` (→ `display`, `monitor`), `gtk_qt` (→ `theme`, `icons`, `font`, `cursor`), `terminalshell` (→ `terminal`, `shell`) and `libc`.
Therefore, do not assume that `modules/<x>/` always has a matching `detection/<x>/`.
### Layer boundaries
| Layer | Owns | Must not |
|---|---|---|
| `options/` | **Global** config (colors, logo, threading, timeouts) | hold per-module options |
| `modules/` | formatting, printing, JSON serialization | read `/proc`, call Win32 APIs, parse sysfs |
| `detection/` | cross-platform data retrieval, clean result structs | print anything, read display config |
| `common/` | general-purpose utilities, no business logic | depend on a specific module |
A simple check: **no file under `detection/` should contain `printf` or read `instance.config`.** Symmetrically, no file under `modules/` should contain `#ifdef __linux__`.
---
## Core architecture: modules vs. detection
This is the most important convention in the codebase. Every feature consists of a fixed set of files; using CPU as the example:
```
modules/cpu/option.h module option struct
modules/cpu/cpu.c formatting and output
detection/cpu/cpu.h platform-independent interface
detection/cpu/cpu_linux.c ┐
detection/cpu/cpu_apple.c │
detection/cpu/cpu_windows.c ├─ platform implementations, one linked per build
detection/cpu/cpu_bsd.c │
detection/cpu/cpu_nosupport.c ┘
```
The interface is deliberately minimal, typically consisting of only two declarations:
```c
typedef struct FFCPUResult { ... } FFCPUResult; // result struct
const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu);
```
The `const char*` return value is an **error string**; `nullptr` means success. This pattern is used throughout `detection/` — please keep it consistent.
Helper functions are only exposed when they are genuinely shared between platform implementations (as in `cpu.h`: `ffCPUAppleCodeToName`, `ffCPUDetectByCpuid`).
**The benefit of this separation:** adding a platform never touches `modules/`; fixing output formatting never touches `detection/`.
---
## Module registration
### The descriptor
Every module exports one `FFModuleBaseInfo` (defined in `common/option.h:46`) — essentially a hand-written vtable:
```c
typedef struct FFModuleBaseInfo {
const char* name; // lookup key, e.g. "cpu"
const char* description; // help text
FFModuleDisplayName displayName; // module name in 20 languages
void (*initOptions)(void* options);
void (*destroyOptions)(void* options);
void (*parseJsonObject)(void* options, struct yyjson_val* module);
bool (*printModule)(void* options);
bool (*generateJsonResult)(void* options, yyjson_mut_doc*, yyjson_mut_val*);
void (*generateJsonConfig)(void* options, yyjson_mut_doc*, yyjson_mut_val*);
FFModuleFormatArgList formatArgs; // format placeholder table
const uint8_t defaultOrder; // sort weight
} FFModuleBaseInfo;
```
The source comment acknowledges that this is undefined behavior, since `void*` is not compatible with `FF*Options*`. It is a pragmatic compromise to obtain polymorphism in C; do not attempt to "fix" it.
### The registry: a first-letter hash bucket
`src/modules/modules.c` defines 26 `static FFModuleBaseInfo*` arrays (`A[]` through `Z[]`), each terminated by `nullptr`, collected into `ffModuleInfos[26]`:
```c
FFModuleBaseInfo** modules = ffModuleInfos[toupper(name[0]) - 'A']; // O(1) bucket lookup
for (; *modules; ++modules) { // linear scan in the bucket
if (ffStrEqualsIgnCase(name, (*modules)->name)) { ... }
}
```
Because the registry is small, a single arithmetic bucket lookup followed by a few string comparisons is preferable to a general-purpose hash table. When adding a module, place its descriptor in the bucket matching the first letter of `.name`, and keep the existing `nullptr` terminator at the end.
### The calling convention: zero heap allocation
Every dispatch site (`jsonconfig.c:98`, `commandoption.c:189`) follows the same pattern:
```c
alignas(uint64_t) uint8_t optionBuf[FF_OPTION_MAX_SIZE]; // 256 bytes, on the stack
baseInfo->initOptions(optionBuf);
baseInfo->parseJsonObject(optionBuf, jsonVal); // JSONC path only
baseInfo->printModule(optionBuf); // or generateJsonResult
baseInfo->destroyOptions(optionBuf);
```
`FF_OPTION_MAX_SIZE = 1 << 8` (256 bytes). Every module's `option.h` must end with:
```c
static_assert(sizeof(FFCPUOptions) <= FF_OPTION_MAX_SIZE, "FFCPUOptions size exceeds maximum allowed size");
```
**In other words, no module option struct may exceed 256 bytes.** This is a hard constraint, enforced at compile time.
The three dispatch entry points:
| Entry point | Location | Used for |
|---|---|---|
| `parseModuleJsonObject` | `common/impl/jsonconfig.c:90` | the `modules[]` array in a JSONC config |
| `parseStructureCommand` | `common/impl/commandoption.c:181` | the colon-separated structure string |
### Build-time module discovery
`CMakeLists.txt:134` globs `src/modules/*/*.c`, keeps only the entries whose file name matches their directory name, and generates a `MODULE_DISABLE_<UPPER>` option for each:
```cmake
file(GLOB FF_MODULE_SRCS CONFIGURE_DEPENDS RELATIVE "..." ".../src/modules/*/*.c")
set(FF_MODULE_DIRS "")
foreach(FF_MODULE_SRC ${FF_MODULE_SRCS})
get_filename_component(FF_MODULE_DIR "${FF_MODULE_SRC}" DIRECTORY)
get_filename_component(FF_MODULE_NAME "${FF_MODULE_SRC}" NAME_WE)
if("${FF_MODULE_DIR}" STREQUAL "${FF_MODULE_NAME}")
list(APPEND FF_MODULE_DIRS "${FF_MODULE_DIR}")
endif()
endforeach()
foreach(FF_MODULE_DIR ${FF_MODULE_DIRS})
string(TOUPPER "${FF_MODULE_DIR}" FF_MODULE_UPPER)
option(MODULE_DISABLE_${FF_MODULE_UPPER} "Disable module ${FF_MODULE_DIR}" OFF)
endforeach()
```
Because the glob matches sources rather than directories, a directory counts as a module only when `src/modules/<name>/<name>.c` exists. Empty directories — which git does not track, so they are easy to leave behind — and stray files are ignored instead of breaking the configure step with `Cannot find source file`.
### Module sources are discovered automatically
`FF_MODULE_DIRS` also drives the source list (`CMakeLists.txt:516`):
```cmake
foreach(FF_MODULE_DIR ${FF_MODULE_DIRS})
list(APPEND LIBFASTFETCH_SRC
src/modules/${FF_MODULE_DIR}/${FF_MODULE_DIR}.c
)
endforeach()
```
Consequences:
- `src/modules/<name>/<name>.c` is compiled as soon as the file exists — **there is no source list to edit for the module layer**.
- The file name must match the directory name. A directory whose `.c` file is named differently, or has none at all, is silently not a module: a typo therefore shows up as a module missing from `fastfetch --list-modules`, not as a build error.
- The glob uses `CONFIGURE_DEPENDS`, so with the Makefile and Ninja generators the build re-evaluates it and re-runs CMake when a module source is added or removed. With other generators, or to be safe, re-run `cmake -B build` explicitly.
Only the module layer is automated. Sources under `src/detection/` and `src/common/impl/` are **not** globbed and must still be listed by hand — see [step 5](#5-add-the-platform-sources-to-cmakeliststxt).
---
## Walkthrough: adding a module
Adding a `Foo` module, step by step.
### 1. Define the option struct
`src/modules/foo/option.h`:
```c
#pragma once
#include "common/option.h"
typedef struct FFFooOptions {
FFModuleArgs moduleArgs; // must be the first field
bool showBar;
} FFFooOptions;
static_assert(sizeof(FFFooOptions) <= FF_OPTION_MAX_SIZE, "FFFooOptions size exceeds maximum allowed size");
```
`FFModuleArgs` must come first. It provides `key`, `format`, `outputColor`, `keyColor`, `keyIcon` and `keyWidth`; because it is the first field, `ffJsonConfigParseModuleArgs()` handles these generically, **so no parsing code is required**.
### 2. Implement detection
`src/detection/foo/foo.h`:
```c
#pragma once
#include "fastfetch.h"
typedef struct FFFooResult {
FFstrbuf name;
uint32_t count;
} FFFooResult;
const char* ffDetectFoo(const FFFooOptions* options, FFFooResult* result);
```
`src/detection/foo/foo_linux.c`:
```c
#include "foo.h"
const char* ffDetectFoo(const FFFooOptions* options, FFFooResult* result) {
// read /sys, /proc, sysfs, dbus, ...
return nullptr; // success; return an error string on failure
}
```
**Write one file per target platform, plus a `foo_nosupport.c` fallback for the remaining platforms.** The repository currently contains 45 `*_nosupport.c` files serving this purpose.
### 3. Implement the module
`src/modules/foo/foo.c` — implement the six functions, then define the descriptor:
```c
FFModuleBaseInfo ffFooModuleInfo = {
.name = "Foo",
.description = "Print foo information",
.displayName = {
.en = "Foo", .ar = "Foo", .cs = "Foo", .de = "Foo", .es = "Foo",
.fr = "Foo", .gl = "Foo", .he = "Foo", .id = "Foo", .it = "Foo",
.ja = "Foo", .ko = "Foo", .pl = "Foo", .pt = "Foo", .ru = "Foo",
.tr = "Foo", .uk = "Foo", .vi = "Foo", .zh_CN = "Foo", .zh_TW = "Foo",
},
.initOptions = (void*) ffInitFooOptions,
.destroyOptions = (void*) ffDestroyFooOptions,
.parseJsonObject = (void*) ffParseFooJsonObject,
.printModule = (void*) ffPrintFoo,
.generateJsonResult = (void*) ffGenerateFooJsonResult,
.generateJsonConfig = (void*) ffGenerateFooJsonConfig,
.formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
{ "Name", "name" },
{ "Count", "count" },
})),
.defaultOrder = 73,
};
```
Points to note:
- **`displayName`** is a literal block of all 20 language fields; there is no shortcut macro, so copy the layout from an existing module: **`en`, `ar`, `cs`, `de`, `es`, `fr`, `gl`, `he`, `id`, `it`, `ja`, `ko`, `pl`, `pt`, `ru`, `tr`, `uk`, `vi`, `zh_CN`, `zh_TW`**.
**Fill in all 20.** The struct is read by byte offset (see [Pitfalls](#6-localization-uses-byte-offsets-not-enums)) and there is **no fallback** — a missing field means the key prints empty in that language.
- **`formatArgs`** must be exhaustive. It drives the placeholder list printed by `fastfetch -h foo-format`; **any placeholder omitted here is neither listed nor usable by the user.**
- The `moduleFormat` section in `doc/json_schema.json` is generated by `fastfetch -h format-json`. Its metadata comes from `FFModuleBaseInfo::formatArgs`. To keep the schema and module descriptors consistent, do not edit the `moduleFormat` section in `doc/json_schema.json` by hand; update the module metadata and regenerate it instead.
- **`defaultOrder`**: use the current maximum plus 1. Search the existing descriptors for `.defaultOrder =` before choosing a value; do not copy a hard-coded value from this document. Leaving it out, or setting it to `0`, excludes the module from the interactive `--gen-config` picker. Only `logo`, `command` and `custom` rely on this behavior, because they require user arguments or are invoked directly by the display layer.
### 4. Register it
- Add `#include "modules/foo/foo.h"` to `src/modules/modules.h`
- Insert into the `F[]` array in `src/modules/modules.c`:
```c
#if !FF_MODULE_DISABLE_FOO
&ffFooModuleInfo,
#endif
```
`FF_MODULE_DISABLE_FOO` is generated by CMake — you do not define it yourself.
### 5. Add the platform sources to `CMakeLists.txt`
The module layer is discovered by glob (see [Build-time module discovery](#module-sources-are-discovered-automatically)), **but `src/detection/**` and `src/common/impl/**` are not**. `CMakeLists.txt` lists them explicitly, inside one mutually exclusive chain of platform blocks:
| Block | Line | Covers |
|---|---|---|
| `if(LINUX)` | `CMakeLists.txt:522` | Linux |
| `elseif(ANDROID)` | `CMakeLists.txt:608` | Android (Termux) |
| `elseif(FreeBSD)` | `CMakeLists.txt:691` | FreeBSD, MidnightBSD, DragonFly |
| `elseif(NetBSD)` | `CMakeLists.txt:788` | NetBSD |
| `elseif(OpenBSD)` | `CMakeLists.txt:872` | OpenBSD |
| `elseif(APPLE)` | `CMakeLists.txt:959` | macOS / iOS |
| `elseif(WIN32)` | `CMakeLists.txt:1046` | Windows |
| `elseif(SunOS)` | `CMakeLists.txt:1121` | Solaris / illumos |
| `elseif(Haiku)` | `CMakeLists.txt:1204` | Haiku |
| `elseif(GNU)` | `CMakeLists.txt:1282` | GNU/Hurd |
Add the platform implementation to every block whose platform it supports, and `foo_nosupport.c` to every remaining block, so that all ten platforms still link:
```cmake
elseif(FreeBSD)
list(APPEND LIBFASTFETCH_SRC
...
src/detection/foo/foo_bsd.c
)
```
Points to note:
- Exactly one block is compiled per build, so a file omitted from a block does not exist for that platform, and the link fails with an undefined reference to `ffDetectFoo()` — **on that platform only**. A missing entry therefore builds fine locally and fails in CI; this is why every block must be covered.
- A platform may reuse another platform's implementation instead of a stub. `src/common/impl/networking_linux.c`, for example, is listed in nine of the ten blocks (all but `WIN32`). Check where the closest sibling module points before adding a new file.
- `DragonFly` is handled by the inner `if(DragonFly)` sub-block inside the FreeBSD block (`CMakeLists.txt:773`); add the variant there, as `processes`, `top` and `wifi` do.
- New helpers under `src/common/impl/` follow the same rule: they are not globbed, and each block that needs one must list it.
- A few files are appended outside the platform chain because they depend on an option or on a specific feature — for example the proprietary GPU backends (`CMakeLists.txt:1379`) and `src/common/impl/wcwidth.c` (`CMakeLists.txt:1408`). Those are written by hand as well.
### 6. Modules that need warm-up
If your module needs a sampling interval (CPU usage) or a network round-trip (public IP, weather), also implement `ffPrepareFoo()` and register it in the switch inside `ffPrepareCommandOption()` in `common/impl/commandoption.c`, under the matching first-letter `case`. Six modules currently do this: CPUUsage, DiskIO, NetIO, PublicIP, Top and Weather.
### 7. Verify
```sh
cmake -B build && cmake --build build -j
./build/fastfetch -s foo --format json # JSON output
./build/fastfetch -h foo-format # list formatArgs placeholders
./build/fastfetch --gen-config # confirm it appears in the picker
```
Note the `-format` suffix on the help flag: `fastfetch -h foo` is not supported; only `fastfetch -h foo-format` works.
If you added detection sources, re-check [step 5](#5-add-the-platform-sources-to-cmakeliststxt) before pushing: a platform block you missed compiles fine locally and fails only when that platform is built.
---
## Walkthrough: adding a logo
A new logo **must** have a corresponding "Logo Request" issue, linked from the PR with `Closes #1234`. Logo PRs without a linked issue are not accepted.
### 1. Add the ASCII file
```
src/logo/ascii/<first-letter>/<distro>.txt
```
For example `src/logo/ascii/d/distro.txt`. Directories are already split by first letter (`a/` … `z/`, plus `_/`).
The file is plain ASCII art with `$1` … `$9` as color placeholders:
```
$3 ,-^-___
$3 /\\\///
$2refined.$1 /\\\\//
```
- `$1` … `$9` map to palette slots 19; at most 9 are supported (`FASTFETCH_LOGO_MAX_COLORS = 9`)
- `$$` is a literal `$`
- Characters without a placeholder inherit the current color. Of the 530 existing logos, 239 use no placeholders at all (monochrome) and 291 do; **new logos should use placeholders**, as monochrome is a legacy style
- Tabs are expanded to 4 spaces
- Colors can be overridden with `--logo-color-1` … `--logo-color-9`
### 2. Register it in the `.inc`
CMake turns each `.txt` file into a `FASTFETCH_DATATEXT_LOGO_<UPPERCASE>` macro (`CMakeLists.txt:418`), but **the registry itself is maintained by hand**. Edit `src/logo/ascii/<first-letter>.inc`:
```c
// src/logo/ascii/d.inc
#ifdef FASTFETCH_DATATEXT_LOGO_DISTRO
// Distro
{
.names = { "Distro" }, // ID (preferred) or NAME from /etc/os-release, do NOT add both
.lines = FASTFETCH_DATATEXT_LOGO_DISTRO,
.colors = {
FF_COLOR_FG_PRIMARY, // recommended for using as WHITE replacement, light-theme terminal friendly
FF_COLOR_FG_BLUE, // preferred
FF_COLOR_FG_256 "34",
FF_COLOR_FG_RGB "0;255;0", // not recommended because of bad compatibility with raw TTY
},
},
#endif
```
- `names` is matched case-insensitively. Do not add names that differ only by case, because they can never be distinguished. Every name is also shown by `--list-logos`, so use user-friendly spelling such as an initial capital where appropriate.
- For a new logo, use exactly one name unless there is a specific compatibility reason to add more. That name should first be the `ID` from `/etc/os-release`. If the ID cannot distinguish this logo from another logo for the same OS, use the `NAME` value instead. `logoGetBuiltinDetected` in `src/logo/logo.c` documents the detection order: `ID`, then `NAME`, then tokens from `ID_LIKE`, then the platform name fallback. Manual `logo-source` selection uses the name directly.
- `colors` is positional — entry 0 is `$1`, entry 1 is `$2`, and so on
- `colors[0]` also becomes the title color and `colors[1]` the key color, unless the user overrides them
If the same OS has multiple logo variants, mark the variant explicitly with `.type`:
```c
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
```
Use `FF_LOGO_LINE_TYPE_ALTER_BIT` for an alternate logo, `FF_LOGO_LINE_TYPE_SMALL_BIT` for a small logo, or combine the flags when both apply. This is also a lookup optimization: a logo marked `FF_LOGO_LINE_TYPE_SMALL_BIT` is considered only for `type = small`, while a logo marked `FF_LOGO_LINE_TYPE_ALTER_BIT` is never selected by automatic detection. Alternate logos are available only when explicitly requested through `-l <source>`.
### 3. Verify
```sh
./build/fastfetch -l distro
./build/fastfetch --list-logos | grep -i distro
```
---
## Platform conventions
The `detection/` layer picks its implementation by **filename suffix**; the choice is made at build time from `CMAKE_SYSTEM_NAME`:
| Suffix | Platform |
|---|---|
| `_linux.c` | Linux |
| `_apple.c` / `_apple.m` | macOS / iOS (`.m` for Objective-C) |
| `_windows.c` / `_windows.cpp` | Windows (`.cpp` for WinRT / WMI) |
| `_bsd.c` | FreeBSD |
| `_nbsd.c` | NetBSD |
| `_obsd.c` | OpenBSD |
| `_sunos.c` | Solaris / illumos |
| `_haiku.c` / `.cpp` | Haiku |
| `_android.c` | Android (Termux) |
| `_gnu.c` | GNU/Hurd |
| `_nosupport.c` | Empty fallback |
Current distribution of platform files in `detection/`:
| Suffix | Files | Suffix | Files |
|---|---|---|---|
| `_linux` | 58 | `_obsd` | 16 |
| `_windows` | 47 | `_haiku` | 13 |
| `_apple` | 46 | `_android` | 12 |
| `_nosupport` | 45 | `_gnu` | 3 |
| `_bsd` | 29 | | |
| `_sunos` | 19 | | |
| `_nbsd` | 17 | | |
(These are repository inventory figures, counting `.c`, `.m`, `.cpp`, and `.h`; they may change as platforms and modules are added.)
**Do not accumulate `#ifdef __linux__` blocks in a single file.** When adding platform support, copy the closest existing implementation and change the suffix.
`common/` follows the same convention: `common/impl/` contains `io_unix.c` / `io_windows.c`, `netif_linux.c` / `netif_apple.c` / `netif_bsd.c` and similar files, with `common/apple/`, `common/windows/` and `common/haiku/` holding platform-specific helpers.
When several platform suffixes could apply, use the most specific implementation supported by the build system (for example, `_nbsd.c` instead of the generic `_bsd.c` on NetBSD). Keep the generic file as the fallback for platforms that share its conventions.
---
## Code style
### Formatting
The project uses clang-format with `BasedOnStyle: LLVM` plus these key overrides:
```yaml
IndentWidth: 4
UseTab: Never
ColumnLimit: 0 # never wrap
InsertBraces: true # braces even on single-statement ifs
PointerAlignment: Left # char* p, not char *p
SortIncludes: Never # include order is managed by hand
AlignAfterOpenBracket: DontAlign
BinPackParameters: false # all params on one line, or one per line
```
Before committing:
```sh
clang-format -i src/modules/foo/*.c src/modules/foo/*.h
```
`src/3rdparty/**`, `build/**` and `src/logo/builtin.c` are listed in `.clang-format-ignore` — **do not reformat them.**
`.editorconfig` specifies LF line endings, a 4-space indent, a final newline, and trailing whitespace trimmed (except in Markdown).
### Naming
| Kind | Convention | Example |
|---|---|---|
| Functions | `ff` + PascalCase | `ffDetectCPU`, `ffPrintCPU` |
| Types | `FF` + PascalCase | `FFCPUResult`, `FFModuleBaseInfo` |
| Variables / fields | camelCase | `coresPhysical`, `keyWidth` |
| Macros | SCREAMING_SNAKE_CASE | `FF_OPTION_MAX_SIZE` |
| Module options | `FF<Name>Options` | `FFCPUOptions` |
| Detection results | `FF<Name>Result` | `FFCPUResult` |
### Spelling
CI runs codespell (`.codespellrc`). Known false positives are listed in `ignore-words-list` (`iterm`, `compiletime`, and various non-English distro words). Add new words there rather than changing the code.
### Compiler warnings
The build enables `-Wall -Wextra -Wconversion` plus several `-Werror`s:
```
-Werror=uninitialized -Werror=return-type -Werror=vla
-Werror=incompatible-pointer-types -Werror=implicit-function-declaration -Werror=int-conversion
```
**`-Wconversion` is strict**: every implicit narrowing conversion needs an explicit cast.
---
## Commit messages
Format:
```
<Scope>[ (Platform)]: <third-person singular verb> <object>
```
Scope is the module or subsystem name; Platform is optional. Use the third-person singular present tense, capitalize the first letter, no trailing period.
Real examples from recent history:
```
Processes (Haiku): honors `options->countKprocs`
WM (macOS): improves reliability of WM plugin detection
Memory (Windows): prefers `NQSI`
Top (Linux): improves performance of `stat` parsing
Logo (Builtin): adds omarchy
Global: introduces global macro `FF_PATH_PKG_BASE` to replace `_PATH_LOCALBASE`
LM (OpenBSD): adds support
CI: disables fail on alert
Doc: updates README
Presets: moves `top` to the bottom of running modules [ci skip]
```
Common verbs: `adds`, `removes`, `fixes`, `improves`, `updates`, `corrects`, `prefers`, `honors`, `disables`, `enables`, `introduces`, `detects`, `reports`, `skips`, `uses`.
Scopes in use: `Top`, `Processes`, `Memory`, `Logo (Builtin)`, `CI`, `Doc`, `Presets`, `Global`, plus individual module names.
Documentation-only changes use a `[ci skip]` suffix.
---
## Changelog
User-visible changes go into `CHANGELOG.md`, under the topmost version heading:
```markdown
# Unreleased
Changes:
* The DE / WM / LM modules now reports the full name ...
Features:
* Added Top module to print processes with the highest CPU, memory or disk I/O usage. (Top)
* Improved Wi-Fi module
* Added Wifi channel width detection, exposed via `{channel-width}` in custom format.
* Improved Wifi channel frequency accuracy on Windows, macOS.
* Added Battery detection support on SunOS. (Battery, SunOS)
Bugfixes:
* Fixed I/O rate calculation precision in DiskIO and NetIO. (DiskIO / NetIO)
```
Rules:
- Three sections: `Changes:` (behavior changes), `Features:`, `Bugfixes:`
- Past tense: `Added` / `Fixed` / `Improved`
- End each entry with its scope: `(Module, Platform)` or `(ModuleA / ModuleB)`
- Sub-bullets are indented 4 spaces
---
## Tests
Tests are standalone executables in `tests/` using a `VERIFY` macro that exits non-zero on failure:
```c
#define VERIFY(expression) \
if (!(expression)) testFailed(&strbuf, #expression, __LINE__)
```
Current tests: `strbuf.c`, `list.c`, `format.c`, `color.c`, `duration.c`, `strutil.c`.
```sh
cmake -B build -DBUILD_TESTS=On
cmake --build build
cd build && ctest --output-on-failure
```
Coverage focuses on the core data structures and the formatting engine in `common/`. The `detection/` layer has no automated tests, because it depends on the state of a running system; it is instead covered by the CI matrix — 20 workflows under `.github/workflows/` spanning Linux (including musl, loong64, armv7l, i686), macOS, Windows, FreeBSD, NetBSD, OpenBSD, DragonFly, Solaris, OmniOS and Haiku, plus spellcheck and benchmark jobs.
**If you modify `common/FFstrbuf.h`, `common/format.h` or `common/color.h`, extend the corresponding test.**
---
## Pull requests
1. **Open an issue first** (feature request / bug report / logo request) to confirm that the change is wanted before investing effort. Templates are in `.github/ISSUE_TEMPLATE/`.
2. Branch off `dev` — **`dev` is the main development branch**, not `master`.
3. Follow the [commit message convention](#commit-messages).
4. Update `CHANGELOG.md` for user-visible changes.
5. Open the PR against `dev` and fill in `.github/pull_request_template.md`:
- Summary
- Related issue (**required for new logos**; otherwise the PR is not accepted)
- Changes
- Screenshots (required for visual changes)
- Checklist: confirm you tested locally
### Pre-submit checklist
```sh
clang-format -i <changed files> # format
codespell # spelling
cmake -B build -DBUILD_TESTS=On && cmake --build build -j
cd build && ctest --output-on-failure # tests
./build/fastfetch --format json # verify JSON output is well-formed
./build/fastfetch -c presets/all.jsonc --stat false # smoke-test every module
```
---
## Pitfalls
The following points are easy to misinterpret when reading this codebase. Most of them follow from the startup-time objective described above.
### 1. Option structs must not exceed 256 bytes
`FF_OPTION_MAX_SIZE = 1 << 8`. Exceeding it is caught at compile time by `static_assert`. Do not attempt to increase the value: it determines the stack cost of every module invocation.
### 2. `FF_MODULE_DISABLE_*` controls registration, not compilation
```c
// verbatim from the top of modules/modules.c:
// FF_MODULE_DISABLE_<module> only controls if the module is registered,
// the module code itself is still compiled.
// We rely `LTO` to remove the unused code (only enabled in Release mode)
```
**Disabling modules in a Debug build does not shrink the binary.** LTO is enabled whenever `CMAKE_BUILD_TYPE != Debug`, and the default `RelWithDebInfo` already satisfies that — so measure size with `RelWithDebInfo` or `Release`, never with `Debug`. (The "Release mode" wording in the comment above is imprecise.)
### 3. Only two things are discovered by glob
The module sources (`CMakeLists.txt:134`) and the logo `.txt` files (`CMakeLists.txt:429`). Both use `CONFIGURE_DEPENDS`, so with the Makefile and Ninja generators the build re-checks the glob and re-runs CMake when the result changes; other generators (Visual Studio and Xcode in particular) do not track it as reliably. Re-run `cmake -B build` after adding a module source or a logo file rather than relying on that behavior.
Everything else — `src/detection/**` and `src/common/impl/**`, and any source outside the platform chain — must be listed in `CMakeLists.txt` by hand; see [step 5](#5-add-the-platform-sources-to-cmakeliststxt).
### 4. CLI module options are removed
Per-module command-line flags such as `--cpu-temp` are **no longer supported**. The only job of `ffParseModuleOptions` now is to translate the flag into a JSON key, then `exit(477)` with a pointer to the config file:
```
Error: Unsupported module option: --cpu-temp
Support of module options has been removed. Please add the flag to the JSON config instead.
Example (demonstration only): `{ "modules": [ { "type": "cpu", "temp": true } ] }`
```
**JSONC is the first-class configuration interface; the command line is not.** When adding module options, implement `parseJsonObject` only — do not add a CLI branch.
### 5. `defaultOrder = 0` hides a module from `--gen-config`
`collectModuleInfos` (`genconfig.c:186`) skips any module whose `defaultOrder` is `0`. C zero-initializes the field, so **omitting it is the same as setting it to 0**. Only `logo`, `command` and `custom` rely on this intentionally.
`defaultOrder` affects only the ordering in the interactive `--gen-config` picker; it has no effect on the runtime output order.
### 6. Localization uses byte offsets, not enums
`instance.config.display.keyLanguage` does not hold a language enum — it holds a **byte offset** such as `offsetof(FFModuleDisplayName, zh_CN)`. The macro `FF_MODULE_GET_DISPLAY_NAME` (`common/option.h:123`) does plain pointer arithmetic with it:
```c
#define FF_MODULE_GET_DISPLAY_NAME(moduleName) \
(*(const char**) ((uint8_t*) &ff ## moduleName ## ModuleInfo.displayName + instance.config.display.keyLanguage))
```
Consequence: **the field order of `FFModuleDisplayName` must never change** — reordering the fields silently corrupts the output for every language.
### 7. The `multithreading` option has limited effect
The global `multithreading` option currently takes effect in exactly one place: `common/impl/networking_linux.c:339`. Modules are still printed sequentially. Modules that need concurrency go through the `ffPrepare*` warm-up hooks instead, which start sampling or fire off requests before the print loop begins.
This may change in the future. The main blocking issue is that there are dependencies between different modules.
### 8. Do not print or read configuration inside `detection/`
The `detection/` layer must stay pure: read system state, fill a struct, return an error string. Any `printf` or any read of `instance.config` there is a design error.
Use `FF_DEBUG` (`src/common/debug.h`) for logging.
### 9. `src/logo/builtin.c` and `3rdparty/` are formatting-exempt
The former is a large generated and hand-maintained data table; the latter is upstream code. Both are excluded via `.clang-format-ignore`; do not reformat either.
---
## Reference
- Configuration guide: <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration>
- JSON schema: `doc/json_schema.json`
- Example presets: `presets/` (`all.jsonc`, `neofetch.jsonc`, `ci.jsonc`, …)
- Man page source: `doc/fastfetch.1.in`
- Code generation scripts: `scripts/` (`gen-pciids.py`, `gen-amdgpuids.py`, `gen-man.py`)
+8 -6
View File
@@ -1,5 +1,6 @@
# Fastfetch
[![Benchmark](https://img.shields.io/badge/GitHub%20Pages-live-blue?logo=github)](https://fastfetch-cli.github.io/fastfetch/dev/bench)
[![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/fastfetch-cli/fastfetch/ci.yml)](https://github.com/fastfetch-cli/fastfetch/actions)
[![GitHub license](https://img.shields.io/github/license/fastfetch-cli/fastfetch)](https://github.com/fastfetch-cli/fastfetch/blob/dev/LICENSE)
[![GitHub contributors](https://img.shields.io/github/contributors/fastfetch-cli/fastfetch)](https://github.com/fastfetch-cli/fastfetch/graphs/contributors)
@@ -99,7 +100,7 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
* Display help messages: `fastfetch --help`
* Generate a minimal config file: `fastfetch [-s <module1>[:<module2>]] --gen-config [</path/to/config.jsonc>]`
* Use: `--gen-config-full` to generate a full config file with all optional options
* Use [The online configuration generator](https://fastfetch-cli.github.io/fastfetch-config/) to generate a full config file with all optional options
## Customization
@@ -199,7 +200,8 @@ See [#1096](https://github.com/fastfetch-cli/fastfetch/issues/1096).
### Q: Fastfetch shows fewer dpkg packages than neofetch. Is it a bug?
Neofetch incorrectly counts `rc` packages (packages that have been removed but still have configuration files remaining). See bug: https://github.com/dylanaraps/neofetch/issues/2278
1. Neofetch incorrectly counts `rc` packages for apt (packages that have been removed but still have configuration files remaining). See bug: https://github.com/dylanaraps/neofetch/issues/2278
2. Neofetch incorrectly counts `gpg-pubkey` as packages for rpm. You may check the results of `dnf list --installed | wc -l` and `rpm -qa | wc -l` to see the difference.
### Q: I use Debian / Ubuntu / Debian-derived distro. My GPU is detected as `XXXX Device XXXX (VGA compatible)`. Is this a bug?
@@ -334,10 +336,10 @@ If you find Fastfetch useful, please consider donating.
Give us a star to show your support!
<a href="https://star-history.com/#fastfetch-cli/fastfetch&Date">
<a href="https://star-history.dera.page/#fastfetch-cli/fastfetch&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=fastfetch-cli/fastfetch&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=fastfetch-cli/fastfetch&type=Date" />
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=fastfetch-cli/fastfetch&type=Date" />
<source media="(prefers-color-scheme: dark)" srcset="https://star-history.dera.page/svg?repos=fastfetch-cli/fastfetch&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://star-history.dera.page/svg?repos=fastfetch-cli/fastfetch&type=Date" />
<img alt="Star History Chart" src="https://star-history.dera.page/svg?repos=fastfetch-cli/fastfetch&type=Date" />
</picture>
</a>
+56 -24
View File
@@ -63,46 +63,78 @@ echo '
import json, subprocess, sys
def escape_fish_dq(s: str) -> str:
"""Escape special characters for Fish double quotes to prevent unexpected expansions. One slash in output needs four slashes in script"""
return str(s).replace("\\\\", "\\\\\\\\").replace("\\"", "\\\\\\"").replace("$", "\\\\$")
def main():
data: dict[str, list[dict]] = json.loads(subprocess.check_output(["fastfetch", "--help-raw"]))
enum_functions = []
complete_commands = []
for key in data:
for flag in data[key]:
if flag["long"] == "logo-color-[1-9]":
long_name = flag.get("long", "")
# Handle pseudo flag logo-color-[1-9]
if long_name == "logo-color-[1-9]":
safe_desc_global = escape_fish_dq(flag.get("desc", ""))
for i in range(1, 10):
print(f"""complete -c fastfetch -d "{flag["desc"]}" -l "logo-color-{i}" -x -a "(__fastfetch_complete_color)" """)
complete_commands.append(f"complete -c fastfetch -d \"{safe_desc_global}\" -l \"logo-color-{i}\" -x -a \"(__fastfetch_complete_color)\"")
continue
if flag.get("pseudo", False):
continue
command_prefix = f"""complete -c fastfetch -d "{flag["desc"]}" -l "{flag["long"]}\""""
safe_desc_global = escape_fish_dq(flag.get("desc", ""))
command_prefix = f"complete -c fastfetch -d \"{safe_desc_global}\" -l \"{long_name}\""
if "short" in flag:
command_prefix += f""" -o {flag["short"]}"""
short_name = flag["short"]
command_prefix += f" -o {short_name}"
if "arg" in flag:
type: str = flag["arg"]["type"]
if type == "bool":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
elif type == "color":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_color)\"")
elif type == "command":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_command)\"")
elif type == "config":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_config)\"")
elif type == "enum":
temp: str = " ".join(flag["arg"]["enum"])
print(f"{command_prefix} -x -a \"{temp}\"")
elif type == "logo":
print(f"{command_prefix} -x -a \"(__fastfetch_complete_logo)\"")
elif type == "structure":
print(f"{command_prefix} -x -a \"(__fish_complete_list : __fastfetch_complete_structure)\"")
elif type == "path":
print(f"{command_prefix} -r -F")
arg_type: str = flag["arg"]["type"]
if arg_type == "bool":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
elif arg_type == "color":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_color)\"")
elif arg_type == "command":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_command)\"")
elif arg_type == "config":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_config)\"")
elif arg_type == "enum":
# Sanitize flag name to create a valid Fish function name
func_name = long_name.replace("-", "_").replace("[", "_").replace("]", "_")
func_name = f"__fastfetch_complete_enum_{func_name}"
# Generate the enum function
func_lines = [f"function {func_name}"]
for enum_val, enum_desc in flag["arg"]["enum"].items():
safe_val = escape_fish_dq(enum_val)
safe_desc = escape_fish_dq(enum_desc)
func_lines.append(f" echo -e \"{safe_val}\\t{safe_desc}\"")
func_lines.append("end\n")
enum_functions.append("\n".join(func_lines))
# Append complete command pointing to the new function
complete_commands.append(f"{command_prefix} -x -a \"({func_name})\"")
elif arg_type == "logo":
complete_commands.append(f"{command_prefix} -x -a \"(__fastfetch_complete_logo)\"")
elif arg_type == "structure":
complete_commands.append(f"{command_prefix} -x -a \"(__fish_complete_list : __fastfetch_complete_structure)\"")
elif arg_type == "path":
complete_commands.append(f"{command_prefix} -r -F")
else:
print(f"{command_prefix} -x")
complete_commands.append(f"{command_prefix} -x")
else:
print(f"{command_prefix} -f")
complete_commands.append(f"{command_prefix} -f")
# Print generated enum functions first, then complete rules
print("\n".join(enum_functions))
print("\n".join(complete_commands))
if __name__ == "__main__":
+60
View File
@@ -1,3 +1,63 @@
fastfetch (2.68.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.68.1
-- Carter Li <zhangsongcui@live.cn> Wed, 02 Sep 2026 10:47:51 +0800
fastfetch (2.68.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.68.0
-- Carter Li <zhangsongcui@live.cn> Tue, 01 Sep 2026 16:34:36 +0800
fastfetch (2.67.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.67.0
-- Carter Li <zhangsongcui@live.cn> Thu, 06 Aug 2026 16:22:22 +0800
fastfetch (2.66.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.66.0
-- Carter Li <zhangsongcui@live.cn> Fri, 10 Jul 2026 15:13:37 +0800
fastfetch (2.65.2~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.65.2
-- Carter Li <zhangsongcui@live.cn> Mon, 29 Jun 2026 10:05:47 +0800
fastfetch (2.65.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.65.1
-- Carter Li <zhangsongcui@live.cn> Wed, 24 Jun 2026 14:21:06 +0800
fastfetch (2.64.2~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.64.2
-- Carter Li <zhangsongcui@live.cn> Mon, 08 Jun 2026 15:45:11 +0800
fastfetch (2.63.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.63.1
-- Carter Li <zhangsongcui@live.cn> Fri, 15 May 2026 09:31:54 +0800
fastfetch (2.63.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.63.0
-- Carter Li <zhangsongcui@live.cn> Wed, 13 May 2026 16:02:28 +0800
fastfetch (2.62.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.62.1
-- Carter Li <zhangsongcui@live.cn> Fri, 24 Apr 2026 15:45:15 +0800
fastfetch (2.62.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.62.0
+1 -1
View File
@@ -2,7 +2,7 @@ Source: fastfetch
Section: universe/utils
Priority: optional
Maintainer: Carter Li <zhangsongcui@live.cn>
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, libefl-all-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
Standards-Version: 4.0.0
Homepage: https://github.com/fastfetch-cli/fastfetch
+1 -1
View File
@@ -10,7 +10,7 @@ SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
ROOT_DIR="$(cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
OUT_DIR="$(dirname "$ROOT_DIR")"
PPA="ppa:zhangsongcui3371/fastfetch"
CODENAMES=( jammy noble plucky questing resolute )
CODENAMES=( jammy noble plucky questing resolute stonking )
DRY_RUN=0
if [[ -d "$OUT_DIR/build" ]]; then
+44 -20
View File
@@ -83,6 +83,16 @@
"type": "num",
"default": 0
}
},
{
"long": "watch",
"short": "w",
"desc": "Alias of dynamic-interval, but the value is in seconds instead of milliseconds. If no value is provided, it defaults to 1 second",
"arg": {
"type": "num",
"optional": true,
"default": 1
}
}
],
"Config": [
@@ -97,26 +107,8 @@
},
{
"long": "gen-config",
"desc": "Generate a minimal config file at the specified path",
"remark": "Defaults to \"~/.config/fastfetch/config.jsonc\". Prints the generated config if <path> is \"-\"",
"arg": {
"type": "path",
"optional": true
}
},
{
"long": "gen-config-full",
"desc": "Generate a full config file with all optional settings at the specified path",
"remark": "Defaults to \"~/.config/fastfetch/config.jsonc\". Prints the generated config if <path> is \"-\"",
"arg": {
"type": "path",
"optional": true
}
},
{
"long": "gen-config-force",
"desc": "Generate a config file at the specified path, overwriting any existing file",
"remark": "Defaults to \"~/.config/fastfetch/config.jsonc\"",
"desc": "Interactively generate a config file at the specified path",
"remark": "Opens an interactive configuration UI when run in a terminal. Falls back to non-interactive generation when env-var `$NO_COLOR` is set or stdin/stdout is not a TTY. Defaults to \"~/.config/fastfetch/config.jsonc\". Prints the generated config if <path> is \"-\"",
"arg": {
"type": "path",
"optional": true
@@ -593,6 +585,38 @@
"default": "string"
}
},
{
"long": "key-language",
"desc": "Specify the language used for module keys",
"remark": "Leave empty for auto-detection based on the system locale. Unsupported locales fall back to English",
"arg": {
"type": "enum",
"default": "en",
"optional": true,
"enum": {
"en": "English",
"ar": "Arabic",
"cs": "Czech",
"de": "German",
"es": "Spanish",
"fr": "French",
"gl": "Galician",
"he": "Hebrew",
"id": "Indonesian",
"it": "Italian",
"ja": "Japanese",
"ko": "Korean",
"pl": "Polish",
"pt": "Portuguese",
"ru": "Russian",
"tr": "Turkish",
"uk": "Ukrainian",
"vi": "Vietnamese",
"zh_CN": "Simplified Chinese",
"zh_TW": "Traditional Chinese"
}
}
},
{
"long": "bright-color",
"desc": "Specify whether keys, title, and ASCII logo should be printed in bright color",
+321 -32
View File
@@ -243,7 +243,7 @@
"oneOf": [
{
"type": "boolean",
"description": "True to show the module only if it succeeded; false to show it only if it failed"
"description": "True to show the module only if the last run succeeded; false to show it only if the last run failed"
},
{
"type": "null",
@@ -313,12 +313,16 @@
"description": "Output format for the `Chassis` module. See Wiki for formatting syntax\n 1. {type}: Chassis type\n 2. {vendor}: Chassis vendor\n 3. {version}: Chassis version\n 4. {serial}: Chassis serial number",
"type": "string"
},
"codecFormat": {
"description": "Output format for the `Codec` module. See Wiki for formatting syntax\n 1. {gpu}: GPU name\n 2. {direction}: Decoder / Encoder\n 3. {types}: Compatibility alias of codec types\n 4. {platform-api}: Platform API used for detection",
"type": "string"
},
"commandFormat": {
"description": "Output format for the `Command` module. See Wiki for formatting syntax\n 1. {result}: Command result",
"type": "string"
},
"cpuFormat": {
"description": "Output format for the `CPU` module. 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",
"description": "Output format for the `CPU` module. 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\n 13. {code-name}: CPU code name\n 14. {technology}: CPU technology",
"type": "string"
},
"cpucacheFormat": {
@@ -334,7 +338,7 @@
"type": "string"
},
"datetimeFormat": {
"description": "Output format for the `DateTime` module. See Wiki for formatting syntax\n 1. {year}: Year\n 2. {year-short}: Last two digits of year\n 3. {month}: Month\n 4. {month-pretty}: Month with leading zero\n 5. {month-name}: Month name\n 6. {month-name-short}: Month name short\n 7. {week}: Week number on year\n 8. {weekday}: Weekday\n 9. {weekday-short}: Weekday short\n 10. {day-in-year}: Day in year\n 11. {day-in-month}: Day in month\n 12. {day-in-week}: Day in week\n 13. {hour}: Hour\n 14. {hour-pretty}: Hour with leading zero\n 15. {hour-12}: Hour 12h format\n 16. {hour-12-pretty}: Hour 12h format with leading zero\n 17. {minute}: Minute\n 18. {minute-pretty}: Minute with leading zero\n 19. {second}: Second\n 20. {second-pretty}: Second with leading zero\n 21. {offset-from-utc}: Offset from UTC in the ISO 8601 format\n 22. {timezone-name}: Locale-dependent timezone name or abbreviation\n 23. {day-pretty}: Day in month with leading zero",
"description": "Output format for the `DateTime` module. See Wiki for formatting syntax\n 1. {year}: Year\n 2. {year-short}: Last two digits of year\n 3. {month}: Month\n 4. {month-pretty}: Month with leading zero\n 5. {month-name}: Month name\n 6. {month-name-short}: Month name short\n 7. {week}: Week number on year\n 8. {weekday}: Weekday\n 9. {weekday-short}: Weekday short\n 10. {day-in-year}: Day in year\n 11. {day-in-month}: Day in month\n 12. {day-in-week}: Day in week\n 13. {hour}: Hour\n 14. {hour-pretty}: Hour with leading zero\n 15. {hour-12}: Hour 12h format\n 16. {hour-12-pretty}: Hour 12h format with leading zero\n 17. {minute}: Minute\n 18. {minute-pretty}: Minute with leading zero\n 19. {second}: Second\n 20. {second-pretty}: Second with leading zero\n 21. {offset-from-utc}: Offset from UTC in the ISO 8601 format\n 22. {timezone-name}: Locale-dependent timezone name or abbreviation\n 23. {day-pretty}: Day in month with leading zero\n 24. {am-pm}: AM or PM",
"type": "string"
},
"deFormat": {
@@ -370,7 +374,7 @@
"type": "string"
},
"gpuFormat": {
"description": "Output format for the `GPU` module. See Wiki for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num\n 19. {core-usage-bar}: Core usage percentage bar\n 20. {memory-type}: Memory type (Windows only)",
"description": "Output format for the `GPU` module. See Wiki for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num\n 19. {core-usage-bar}: Core usage percentage bar\n 20. {memory-type}: Memory type (Windows only)\n 21. {pcie-max-speed}: PCIe maximum speed in gen and lanes\n 22. {pcie-curr-speed}: PCIe current speed in gen and lanes",
"type": "string"
},
"hostFormat": {
@@ -394,7 +398,7 @@
"type": "string"
},
"lmFormat": {
"description": "Output format for the `LM` module. See Wiki for formatting syntax\n 1. {service}: LM service\n 2. {type}: LM type\n 3. {version}: LM version",
"description": "Output format for the `LM` module. See Wiki for formatting syntax\n 1. {service}: LM service / process name\n 2. {pretty-name}: LM pretty name\n 3. {version}: LM version",
"type": "string"
},
"loadavgFormat": {
@@ -410,7 +414,7 @@
"type": "string"
},
"mediaFormat": {
"description": "Output format for the `Media` module. See Wiki for formatting syntax\n 1. {combined}: Pretty media name\n 2. {title}: Media name\n 3. {artist}: Artist name\n 4. {album}: Album name\n 5. {status}: Status",
"description": "Output format for the `Media` module. See Wiki for formatting syntax\n 1. {combined}: Pretty media name\n 2. {title}: Media name\n 3. {artist}: Artist name\n 4. {album}: Album name\n 5. {status}: Status\n 6. {progress}: Progress in text\n 7. {progress-num}: Progress in percentage (number)\n 8. {progress-bar}: Progress in percentage (bar)\n 9. {player-name}: Player name\n 10. {player-id}: Player ID\n 11. {url}: URL",
"type": "string"
},
"memoryFormat": {
@@ -442,7 +446,7 @@
"type": "string"
},
"packagesFormat": {
"description": "Output format for the `Packages` module. 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",
"description": "Output format for the `Packages` module. See Wiki for formatting syntax\n 1. {am-system}: Number of am-system packages\n 2. {am-user}: Number of am-user (aka appman) packages\n 3. {appimage}: Number of appimage packages\n 4. {apk}: Number of apk packages\n 5. {brew}: Number of brew packages\n 6. {brew-cask}: Number of brew-cask packages\n 7. {cards}: Number of cards packages\n 8. {choco}: Number of choco packages\n 9. {crux}: Number of crux packages\n 10. {dpkg}: Number of dpkg packages\n 11. {emerge}: Number of emerge packages\n 12. {eopkg}: Number of eopkg packages\n 13. {flatpak-system}: Number of flatpak-system app packages\n 14. {flatpak-user}: Number of flatpak-user app packages\n 15. {guix-home}: Number of guix-home packages\n 16. {guix-system}: Number of guix-system packages\n 17. {guix-user}: Number of guix-user packages\n 18. {hpkg-system}: Number of hpkg-system packages\n 19. {hpkg-user}: Number of hpkg-user packages\n 20. {install-release}: Number of install-release packages\n 21. {kiss}: Number of kiss packages\n 22. {linglong}: Number of linglong packages\n 23. {lpkg}: Number of lpkg packages\n 24. {lpkgbuild}: Number of lpkgbuild packages\n 25. {macports}: Number of macports packages\n 26. {mport}: Number of mport packages\n 27. {moss}: Number of moss packages\n 28. {nix-default}: Number of nix-default packages\n 29. {nix-system}: Number of nix-system packages\n 30. {nix-user}: Number of nix-user packages\n 31. {opkg}: Number of opkg packages\n 32. {pacman}: Number of pacman packages\n 33. {pacman-branch}: Pacman branch on manjaro\n 34. {pacstall}: Number of pacstall packages\n 35. {paludis}: Number of paludis packages\n 36. {pisi}: Number of pisi packages\n 37. {pkg}: Number of pkg packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {pkgtool}: Number of pkgtool packages\n 40. {porg}: Number of porg packages\n 41. {rpm}: Number of rpm packages\n 42. {scoop-global}: Number of scoop-global packages\n 43. {scoop-user}: Number of scoop-user packages\n 44. {snap}: Number of snap packages\n 45. {soar}: Number of soar packages\n 46. {sorcery}: Number of sorcery packages\n 47. {winget}: Number of winget packages\n 48. {xbps}: Number of xbps packages\n 49. {brew-all}: Total number of all brew packages\n 50. {flatpak-all}: Total number of all flatpak app packages\n 51. {guix-all}: Total number of all guix packages\n 52. {hpkg-all}: Total number of all hpkg packages\n 53. {nix-all}: Total number of all nix packages\n 54. {all}: Number of all packages",
"type": "string"
},
"physicaldiskFormat": {
@@ -501,6 +505,10 @@
"description": "Output format for the `Title` module. 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"
},
"topFormat": {
"description": "Output format for the `Top` module. See Wiki for formatting syntax\n 1. {name}: Process name\n 2. {pid}: Process ID\n 3. {cpu}: CPU usage\n 4. {mem}: Memory usage (RSS) in bytes\n 5. {disk-read}: Disk read bytes per second (0 if unsupported)\n 6. {disk-write}: Disk write bytes per second (0 if unsupported)\n 7. {threads}: Number of threads\n 8. {cpu-percentage}: CPU usage percentage\n 9. {mem-formatted}: Memory usage (RSS) formatted\n 10. {disk-read-formatted}: Disk read formatted\n 11. {disk-write-formatted}: Disk write formatted",
"type": "string"
},
"themeFormat": {
"description": "Output format for the `Theme` module. See Wiki for formatting syntax\n 1. {theme1}: Theme part 1\n 2. {theme2}: Theme part 2",
"type": "string"
@@ -538,7 +546,7 @@
"type": "string"
},
"wifiFormat": {
"description": "Output format for the `Wifi` module. See Wiki for formatting syntax\n 1. {inf-desc}: Interface description\n 2. {inf-status}: Interface status\n 3. {status}: Connection status\n 4. {ssid}: Connection SSID\n 5. {bssid}: Connection BSSID\n 6. {protocol}: Connection protocol\n 7. {signal-quality}: Connection signal quality (percentage num)\n 8. {rx-rate}: Connection RX rate\n 9. {tx-rate}: Connection TX rate\n 10. {security}: Connection Security algorithm\n 11. {signal-quality-bar}: Connection signal quality (percentage bar)\n 12. {channel}: Connection channel number\n 13. {band}: Connection channel band in GHz",
"description": "Output format for the `Wifi` module. See Wiki for formatting syntax\n 1. {inf-desc}: Interface description\n 2. {inf-status}: Interface status\n 3. {status}: Connection status\n 4. {ssid}: Connection SSID\n 5. {bssid}: Connection BSSID\n 6. {protocol}: Connection protocol\n 7. {signal-quality}: Connection signal quality (percentage num)\n 8. {rx-rate}: Connection RX rate\n 9. {tx-rate}: Connection TX rate\n 10. {security}: Connection Security algorithm\n 11. {signal-quality-bar}: Connection signal quality (percentage bar)\n 12. {channel}: Connection channel number\n 13. {channel-width}: Connection channel width in MHz\n 14. {band}: Connection channel band in GHz",
"type": "string"
},
"wmthemeFormat": {
@@ -731,6 +739,11 @@
"description": "Top padding of the logo",
"minimum": 0
},
"bottom": {
"type": "integer",
"description": "Bottom padding of the logo; only supported when position is `top`",
"minimum": 0
},
"left": {
"type": "integer",
"description": "Left padding of the logo",
@@ -898,21 +911,11 @@
],
"default": false
},
"wmiTimeout": {
"type": "integer",
"description": "Set the timeout (ms) for WMI queries, `-1` for no timeout. Windows only",
"default": 5000
},
"processingTimeout": {
"type": "integer",
"description": "Set the timeout (ms) when waiting for child processes, `-1` for no timeout",
"default": 5000
},
"preRun": {
"type": "string",
"description": "Command to run before printing logos",
"default": ""
},
"detectVersion": {
"type": "boolean",
"description": "Whether to detect and display component versions. Mainly for benchmarking",
@@ -1058,6 +1061,116 @@
"description": "Left padding for keys",
"minimum": 0,
"default": 0
},
"language": {
"description": "Language used for module keys. `null` for auto detection based on system locale",
"oneOf": [
{
"type": "null",
"description": "Auto detection based on system locale"
},
{
"type": "string",
"const": "en",
"description": "English"
},
{
"type": "string",
"const": "ar",
"description": "Arabic"
},
{
"type": "string",
"const": "cs",
"description": "Czech"
},
{
"type": "string",
"const": "de",
"description": "German"
},
{
"type": "string",
"const": "es",
"description": "Spanish"
},
{
"type": "string",
"const": "fr",
"description": "French"
},
{
"type": "string",
"const": "gl",
"description": "Galician"
},
{
"type": "string",
"const": "he",
"description": "Hebrew"
},
{
"type": "string",
"const": "id",
"description": "Indonesian"
},
{
"type": "string",
"const": "it",
"description": "Italian"
},
{
"type": "string",
"const": "ja",
"description": "Japanese"
},
{
"type": "string",
"const": "ko",
"description": "Korean"
},
{
"type": "string",
"const": "pl",
"description": "Polish"
},
{
"type": "string",
"const": "pt",
"description": "Portuguese"
},
{
"type": "string",
"const": "ru",
"description": "Russian"
},
{
"type": "string",
"const": "tr",
"description": "Turkish"
},
{
"type": "string",
"const": "uk",
"description": "Ukrainian"
},
{
"type": "string",
"const": "vi",
"description": "Vietnamese"
},
{
"type": "string",
"const": "zh_CN",
"description": "Simplified Chinese"
},
{
"type": "string",
"const": "zh_TW",
"description": "Traditional Chinese"
}
],
"default": "en"
}
}
},
@@ -1445,6 +1558,7 @@
"cpu",
"cpucache",
"cpuusage",
"codec",
"command",
"colors",
"cursor",
@@ -1482,6 +1596,7 @@
"poweradapter",
"processes",
"publicip",
"top",
"separator",
"shell",
"sound",
@@ -1540,11 +1655,6 @@
"const": "battery",
"description": "Print battery information"
},
"useSetupApi": {
"description": "Whether to use the `CM API` on Windows to detect battery information. Supports multiple batteries, but is slower (Windows only)",
"type": "boolean",
"default": false
},
"temp": {
"$ref": "#/$defs/temperature"
},
@@ -1755,10 +1865,18 @@
"$ref": "#/$defs/percent"
},
"ddcciSleep": {
"type": "integer",
"description": "Sleep time in milliseconds between DDC/CI requests\nSee <https://www.ddcutil.com/performance_options/#option-sleep-multiplier> for details",
"minimum": 0,
"maximum": 400,
"description": "Sleep time in milliseconds between DDC/CI requests\nSet to null to skip DDC/CI detection\nSee <https://www.ddcutil.com/performance_options/#option-sleep-multiplier> for details",
"oneOf": [
{
"type": "null",
"description": "Skip DDC/CI detection"
},
{
"type": "integer",
"minimum": 0,
"maximum": 400
}
],
"default": 10
},
"compact": {
@@ -1888,6 +2006,67 @@
}
}
},
{
"title": "Codec",
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"const": "codec",
"description": "Print hardware video acceleration codec types (decode / encode)"
},
"splitGPU": {
"description": "Whether to print each GPU separately. If false, merge codecs from all GPUs",
"type": "boolean",
"default": false
},
"useVulkan": {
"description": "Whether to use Vulkan for codec detection instead of other platform-specific APIs",
"type": "boolean",
"default": false
},
"showType": {
"description": "Which types of codecs to detect and show",
"type": "string",
"oneOf": [
{
"const": "both",
"description": "Show both decoders and encoders"
},
{
"const": "decoder",
"description": "Show only decoders"
},
{
"const": "encoder",
"description": "Show only encoders"
}
],
"default": "both"
},
"key": {
"$ref": "#/$defs/key"
},
"keyColor": {
"$ref": "#/$defs/keyColor"
},
"keyIcon": {
"$ref": "#/$defs/keyIcon"
},
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"outputColor": {
"$ref": "#/$defs/outputColor"
},
"format": {
"$ref": "#/$defs/codecFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
{
"title": "CPU",
"type": "object",
@@ -2521,8 +2700,8 @@
},
"waitTime": {
"type": "integer",
"description": "Wait time (in ms). Disk I/O = (totalBytesEnd - totalBytesStart) / waitTime",
"default": 200,
"description": "Wait time (in ms) used to measure the I/O rate (calculated in bytes/sec).\nAvoid setting this too low, as the kernel requires time to accurately update counters.\nIgnored if 'detectTotal' is true.",
"default": 500,
"minimum": 1
},
"key": {
@@ -2781,6 +2960,10 @@
"const": "opencl",
"description": "Use OpenCL API.\nSlow and requires proper OpenCL drivers to be installed"
},
{
"const": "egl-ext",
"description": "Use EGL_EXT_device_enumeration and EGL_EXT_device_query APIs.\nSlow and only detects GPUs that support these extensions"
},
{
"const": "opengl",
"description": "Use OpenGL API.\nSlow and only detects one GPU.\nUsed for OpenBSD"
@@ -3259,6 +3442,9 @@
"const": "media",
"description": "Print the name of the currently playing song"
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
@@ -3415,8 +3601,8 @@
},
"waitTime": {
"type": "integer",
"description": "Wait time (in ms). Net I/O = (totalBytesEnd - totalBytesStart) / waitTime",
"default": 200,
"description": "Wait time (in ms) used to measure the I/O rate (calculated in bytes/sec).\nAvoid setting this too low, as the kernel requires time to accurately update counters.\nIgnored if 'detectTotal' is true.",
"default": 500,
"minimum": 1
},
"key": {
@@ -3577,6 +3763,7 @@
"apk",
"brew",
"choco",
"crux",
"dpkg",
"emerge",
"eopkg",
@@ -3798,7 +3985,12 @@
"properties": {
"type": {
"const": "processes",
"description": "Print the number of running processes"
"description": "Print the number of running processes and threads"
},
"countKprocs": {
"description": "Whether to take kernel processes and threads into account",
"type": "boolean",
"default": false
},
"key": {
"$ref": "#/$defs/key"
@@ -4243,6 +4435,103 @@
}
}
},
{
"title": "Top",
"type": "object",
"additionalProperties": false,
"properties": {
"type": {
"const": "top",
"description": "Print processes with the highest CPU, memory, disk I/O usage, latest start time or thread count"
},
"sort": {
"type": "string",
"description": "Sort processes by CPU, memory, disk IO usage, start time or thread count",
"enum": [
"cpu",
"memory",
"disk-read",
"disk-write",
"start-time",
"threads"
],
"default": "cpu"
},
"showTypes": {
"description": "Specify which resource usages are detected and displayed.\nIf memory or threads is enabled is enabled alone, only a single process snapshot is taken and `waitTime` sampling wait is skipped",
"default": [
"cpu",
"memory",
"disk"
],
"oneOf": [
{
"type": "string",
"enum": [
"cpu",
"memory",
"disk",
"threads"
]
},
{
"type": "array",
"minItems": 1,
"items": {
"type": "string",
"enum": [
"cpu",
"memory",
"disk",
"threads"
]
}
}
]
},
"processes": {
"type": "integer",
"description": "Number of top processes to print",
"minimum": 1,
"default": 5
},
"waitTime": {
"type": "integer",
"description": "Wait time between process samples, in milliseconds. Ignored when showTypes contains \"memory\" only",
"minimum": 1,
"default": 500
},
"compact": {
"type": "boolean",
"description": "Print all process on a single line",
"default": false
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
"keyColor": {
"$ref": "#/$defs/keyColor"
},
"keyIcon": {
"$ref": "#/$defs/keyIcon"
},
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"outputColor": {
"$ref": "#/$defs/outputColor"
},
"format": {
"$ref": "#/$defs/topFormat"
},
"condition": {
"$ref": "#/$defs/conditions"
}
}
},
{
"title": "TPM",
"type": "object",
+9 -4
View File
@@ -50,6 +50,10 @@
"driverSpecific": true,
"temp": true
},
{
"type": "codec",
"splitGPU": true
},
"memory",
"physicalmemory",
{
@@ -95,16 +99,17 @@
"gamepad",
"mouse",
"keyboard",
{
"type": "weather",
"timeout": 1000
},
"top",
"netio",
"diskio",
{
"type": "physicaldisk",
"temp": true
},
{
"type": "weather",
"timeout": 1000
},
"tpm",
"version",
"break",
+11 -6
View File
@@ -52,6 +52,10 @@
"driverSpecific": true,
"temp": true
},
{
"type": "codec",
"splitGPU": true
},
"memory",
"physicalmemory",
{
@@ -90,23 +94,24 @@
"opengl",
"opencl",
"users",
// "bluetooth", // doesn't work on macOS because it requires bluetooth permissions
// "bluetoothradio",
"bluetooth",
"bluetoothradio",
"sound",
"camera",
"gamepad",
"mouse",
"keyboard",
{
"type": "weather",
"timeout": 1000
},
"top",
"netio",
"diskio",
{
"type": "physicaldisk",
"temp": true
},
{
"type": "weather",
"timeout": 1000
},
"tpm",
"version",
"logo",
+13 -16
View File
@@ -1,6 +1,3 @@
// Load with --config examples/2.jsonc
// Note that you must replace the image path to an existing image to display it.
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
@@ -45,12 +42,12 @@
},
{
"type": "kernel",
"key": "│ ├",
"key": "│ ├{icon}",
"keyColor": "yellow"
},
{
"type": "packages",
"key": "│ ├󰏖",
"key": "│ ├{icon}",
"keyColor": "yellow"
},
{
@@ -65,22 +62,22 @@
},
{
"type": "lm",
"key": "│ ├󰧨",
"key": "│ ├{icon}",
"keyColor": "blue"
},
{
"type": "wmtheme",
"key": "│ ├󰉼",
"key": "│ ├{icon}",
"keyColor": "blue"
},
{
"type": "icons",
"key": "│ ├󰀻",
"key": "│ ├{icon}",
"keyColor": "blue"
},
{
"type": "terminal",
"key": "│ ├",
"key": "│ ├{icon}",
"keyColor": "blue"
},
{
@@ -95,32 +92,32 @@
},
{
"type": "cpu",
"key": "│ ├󰻠",
"key": "│ ├{icon}",
"keyColor": "green"
},
{
"type": "gpu",
"key": "│ ├󰍛",
"key": "│ ├{icon}",
"keyColor": "green"
},
{
"type": "disk",
"key": "│ ├",
"key": "│ ├{icon}",
"keyColor": "green"
},
{
"type": "memory",
"key": "│ ├󰑭",
"key": "│ ├{icon}",
"keyColor": "green"
},
{
"type": "swap",
"key": "│ ├󰓡",
"key": "│ ├{icon}",
"keyColor": "green"
},
{
"type": "uptime",
"key": "│ ├󰅐",
"key": "│ ├{icon}",
"keyColor": "green"
},
{
@@ -135,7 +132,7 @@
},
{
"type": "player",
"key": "│ ├󰥠",
"key": "│ ├{icon}",
"keyColor": "cyan"
},
{
+1 -1
View File
@@ -1,4 +1,4 @@
// Inspired by Catnap
// Inspired by Catnap (https://github.com/iinsertNameHere/catnap)
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
+2 -2
View File
@@ -1,4 +1,4 @@
// Inspired by Catnap
// Inspired by Catnap (https://github.com/iinsertNameHere/catnap)
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
@@ -12,7 +12,7 @@
},
"modules": [
{
// draw borders first to make colors of left and right border consistant
// draw borders first to make colors of left and right border consistent
"key": " user",
"type": "title",
"format": "{user-name}",
+1 -1
View File
@@ -1,4 +1,4 @@
// Inspired by Catnap
// Inspired by Catnap (https://github.com/iinsertNameHere/catnap)
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
+1 -1
View File
@@ -1,4 +1,4 @@
// Inspired by Catnap
// Inspired by Catnap (https://github.com/iinsertNameHere/catnap)
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
-3
View File
@@ -1,6 +1,3 @@
// Load with --config examples/2.jsonc
// Note that you must replace the image path to an existing image to display it.
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"display": {
-3
View File
@@ -1,6 +1,3 @@
// Load with --config examples/2.jsonc
// Note that you must replace the image path to an existing image to display it.
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
+7
View File
@@ -16,6 +16,13 @@
"separator",
"os",
"host",
{
"type": "board",
"key": "Host",
"condition": {
"succeeded": false
}
},
{
"type": "kernel",
"format": "{release}"
+1 -1
View File
@@ -33,7 +33,7 @@ endBold = r"\fR" # end bold text tag
# path to the current directory
pathToCurrentDir = path.dirname(__file__)
# path to the JSON option file
pathToHelpFile = path.join(pathToCurrentDir, "../src/data/help.json")
pathToHelpFile = path.join(pathToCurrentDir, "../doc/help.json")
# man page section
manSection = 1
# title (center header)
+141 -88
View File
@@ -21,7 +21,7 @@
// SOFTWARE.
/// \file adl_defines.h
/// \brief Contains all definitions exposed by ADL for \ALL platforms.\n <b>Included in ADL SDK</b>
/// \brief Contains all definitions exposed by ADL for \WIN platforms.\n <b>Included in ADL SDK</b>
///
/// This file contains all definitions used by ADL.
/// The ADL definitions include the following:
@@ -61,6 +61,8 @@
#define ADL_ADAPTER_INDEX_ALL -1
/// Defines APIs with iOption none
#define ADL_MAIN_API_OPTION_NONE 0
/// Defines the maximum of RPC endpoint
#define ADL_MAX_RPC_ENDPOINT 32
/// @}
/// \name Definitions for iOption parameter used by
@@ -141,6 +143,12 @@
#define ADL_ERR_FEATURESYNC_NOT_STARTED -24
/// Adapter is in an invalid power state
#define ADL_ERR_INVALID_POWER_STATE -25
/// The RPC server is in busy state
#define ADL_ERR_SERVER_BUSY -26
/// The GPU is occupied by application which cannot be powered off
#define ADL_ERR_GPU_IN_USE -27
/// The general RPC connection error
#define ADL_ERR_RPC -28
/// @}
/// </A>
@@ -380,6 +388,7 @@
#define ADL_BUSTYPE_PCIE_GEN2 3 /* PCI Express 2nd generation bus */
#define ADL_BUSTYPE_PCIE_GEN3 4 /* PCI Express 3rd generation bus */
#define ADL_BUSTYPE_PCIE_GEN4 5 /* PCI Express 4th generation bus */
#define ADL_BUSTYPE_PCIE_GEN5 6 /* PCI Express 5th generation bus */
/// @}
/// \defgroup define_ws_caps Workstation Capabilities
@@ -872,7 +881,7 @@
typedef enum ADLThreadingModel
{
ADL_THREADING_UNLOCKED = 0, /*!< Default behavior. ADL will not enforce serialization of ADL API executions by multiple threads. Multiple threads will be allowed to enter to ADL at the same time. Note that ADL library is not guaranteed to be thread-safe. Client that calls ADL_Main_Control_Create have to provide its own mechanism for ADL calls serialization. */
ADL_THREADING_LOCKED /*!< ADL will enforce serialization of ADL API when called by multiple threads. Only single thread will be allowed to enter ADL API at the time. This option makes ADL calls thread-safe. You shouldn't use this option if ADL calls will be executed on Linux on x-server rendering thread. It can cause the application to hung. */
ADL_THREADING_LOCKED /*!< ADL will enforce serialization of ADL API when called by multiple threads. Only single thread will be allowed to enter ADL API at the time. This option makes ADL calls thread-safe. */
}ADLThreadingModel;
/// @}
@@ -1844,12 +1853,12 @@ enum ADLOD8FeatureControl
ADL_OD8_TEMPERATURE_FAN = 1 << 6, //FanTargetTemperature
ADL_OD8_TEMPERATURE_SYSTEM = 1 << 7, //MaxOpTemp
ADL_OD8_MEMORY_TIMING_TUNE = 1 << 8,
ADL_OD8_FAN_ZERO_RPM_CONTROL = 1 << 9 ,
ADL_OD8_AUTO_UV_ENGINE = 1 << 10, //Auto under voltage
ADL_OD8_AUTO_OC_ENGINE = 1 << 11, //Auto overclock engine
ADL_OD8_AUTO_OC_MEMORY = 1 << 12, //Auto overclock memory
ADL_OD8_FAN_CURVE = 1 << 13, //Fan curve
ADL_OD8_WS_AUTO_FAN_ACOUSTIC_LIMIT = 1 << 14, //Workstation Manual Fan controller
ADL_OD8_FAN_ZERO_RPM_CONTROL = 1 << 9,
ADL_OD8_AUTO_UV_ENGINE = 1 << 10, //Auto under voltage
ADL_OD8_AUTO_OC_ENGINE = 1 << 11, //Auto overclock engine
ADL_OD8_AUTO_OC_MEMORY = 1 << 12, //Auto overclock memory
ADL_OD8_FAN_CURVE = 1 << 13, //Fan curve
ADL_OD8_WS_AUTO_FAN_ACOUSTIC_LIMIT = 1 << 14, //Workstation Manual Fan controller
ADL_OD8_GFXCLK_QUADRATIC_CURVE = 1 << 15,
ADL_OD8_OPTIMIZED_GPU_POWER_MODE = 1 << 16,
ADL_OD8_ODVOLTAGE_LIMIT = 1 << 17,
@@ -1860,43 +1869,45 @@ enum ADLOD8FeatureControl
ADL_OD8_TDC_LIMIT = 1 << 22, //TDC slider
ADL_OD8_FULL_CONTROL_MODE = 1 << 23, //Full control
ADL_OD8_POWER_SAVING_FEATURE_CONTROL = 1 << 24, //Power saving feature control
ADL_OD8_POWER_GAUGE = 1 << 25 //Power Gauge
ADL_OD8_ACTIMING_PARAMETERS_TUNE = 1 << 25, // AC Timing Parameters Tuning
ADL_OD8_OVERDRIVE_INTERFACE = 1 << 26, // Version info feature ID for RSX, do not expose in ADL.
ADL_OD8_AUTO_UV_ENGINE_V2 = 1 << 27, // Auto UV 2.0 with actual stress testing.
ADL_OD8_POWER_GAUGE = 1 << 28 //Power Gauge
};
typedef enum ADLOD8SettingId
{
OD8_GFXCLK_FMAX = 0,
OD8_GFXCLK_FMIN,
OD8_GFXCLK_FREQ1,
OD8_GFXCLK_VOLTAGE1,
OD8_GFXCLK_FREQ2,
OD8_GFXCLK_VOLTAGE2,
OD8_GFXCLK_FREQ3,
OD8_GFXCLK_VOLTAGE3,
OD8_UCLK_FMAX,
OD8_POWER_PERCENTAGE,
OD8_FAN_MIN_SPEED,
OD8_FAN_ACOUSTIC_LIMIT,
OD8_FAN_TARGET_TEMP,
OD8_OPERATING_TEMP_MAX,
OD8_AC_TIMING,
OD8_FAN_ZERORPM_CONTROL,
OD8_AUTO_UV_ENGINE_CONTROL,
OD8_AUTO_OC_ENGINE_CONTROL,
OD8_AUTO_OC_MEMORY_CONTROL,
OD8_FAN_CURVE_TEMPERATURE_1,
OD8_FAN_CURVE_SPEED_1,
OD8_FAN_CURVE_TEMPERATURE_2,
OD8_FAN_CURVE_SPEED_2,
OD8_FAN_CURVE_TEMPERATURE_3,
OD8_FAN_CURVE_SPEED_3,
OD8_FAN_CURVE_TEMPERATURE_4,
OD8_FAN_CURVE_SPEED_4,
OD8_FAN_CURVE_TEMPERATURE_5,
OD8_FAN_CURVE_SPEED_5,
OD8_WS_FAN_AUTO_FAN_ACOUSTIC_LIMIT,
OD8_GFXCLK_CURVE_COEFFICIENT_A, // As part of the agreement with UI team, the min/max voltage limits for the
OD8_GFXCLK_FMAX = 0,
OD8_GFXCLK_FMIN,
OD8_GFXCLK_FREQ1,
OD8_GFXCLK_VOLTAGE1,
OD8_GFXCLK_FREQ2,
OD8_GFXCLK_VOLTAGE2,
OD8_GFXCLK_FREQ3,
OD8_GFXCLK_VOLTAGE3,
OD8_UCLK_FMAX,
OD8_POWER_PERCENTAGE,
OD8_FAN_MIN_SPEED, //10
OD8_FAN_ACOUSTIC_LIMIT,
OD8_FAN_TARGET_TEMP,
OD8_OPERATING_TEMP_MAX,
OD8_AC_TIMING,
OD8_FAN_ZERORPM_CONTROL,
OD8_AUTO_UV_ENGINE_CONTROL,
OD8_AUTO_OC_ENGINE_CONTROL,
OD8_AUTO_OC_MEMORY_CONTROL,
OD8_FAN_CURVE_TEMPERATURE_1,
OD8_FAN_CURVE_SPEED_1, //20
OD8_FAN_CURVE_TEMPERATURE_2,
OD8_FAN_CURVE_SPEED_2,
OD8_FAN_CURVE_TEMPERATURE_3,
OD8_FAN_CURVE_SPEED_3,
OD8_FAN_CURVE_TEMPERATURE_4,
OD8_FAN_CURVE_SPEED_4,
OD8_FAN_CURVE_TEMPERATURE_5,
OD8_FAN_CURVE_SPEED_5,
OD8_WS_FAN_AUTO_FAN_ACOUSTIC_LIMIT,
OD8_GFXCLK_CURVE_COEFFICIENT_A, // 30 As part of the agreement with UI team, the min/max voltage limits for the
OD8_GFXCLK_CURVE_COEFFICIENT_B, // quadratic curve graph will be stored in the min and max limits of
OD8_GFXCLK_CURVE_COEFFICIENT_C, // coefficient a, b and c. A, b and c themselves do not have limits.
OD8_GFXCLK_CURVE_VFT_FMIN,
@@ -1906,7 +1917,7 @@ typedef enum ADLOD8SettingId
OD8_OD_VOLTAGE,// RSX - voltage offset feature
OD8_ADV_OC_LIMITS_SETTING,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_1,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_2,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_2, //40
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_3,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_4,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_5,
@@ -1915,8 +1926,33 @@ typedef enum ADLOD8SettingId
OD8_GFX_VOLTAGE_LIMIT_SETTING,
OD8_TDC_PERCENTAGE,
OD8_FULL_CONTROL_MODE_SETTING,
OD8_FULL_CONTROL_MODE_GFXCLK,
OD8_FULL_CONTROL_MODE_UCLK, // 50,
OD8_IDLE_POWER_SAVING_FEATURE_CONTROL,
OD8_RUNTIME_POWER_SAVING_FEATURE_CONTROL,
OD8_FULL_CONTROL_MODE_FEATURE_CONTROL,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_1,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_2,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_3,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_4,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_5,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_6,
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_VOLTAGE_LIMIT, //60
OD8_ACTIMING_PARAMETER_TRRDS,
OD8_ACTIMING_PARAMETER_TCL,
OD8_ACTIMING_PARAMETER_TCWL,
OD8_ACTIMING_PARAMETER_TRCDRD,
OD8_ACTIMING_PARAMETER_TRCDWR,
OD8_ACTIMING_PARAMETER_TRAS,
OD8_ACTIMING_PARAMETER_TRPAB,
OD8_ACTIMING_PARAMETER_TRFC,
OD8_ACTIMING_PARAMETER_TRFCPB,
OD8_ACTIMING_PARAMETER_TRREFD, //70
OD8_ACTIMING_PARAMETER_TREF,
OD8_ACTIMING_PARAMETER_TWR,
OD8_ACTIMING_PARAMETER_TWTRS,
OD8_OVERDRIVE_INTERFACE_ID, //74
OD8_AUTO_UV_ENGINE_V2_ID, //75
OD8_POWER_GAUGE,
OD8_COUNT
} ADLOD8SettingId;
@@ -1980,28 +2016,28 @@ typedef enum ADLSensorType
PMLOG_SSDGPU_POWERLIMIT = 49, // DGPU Power limit
PMLOG_TEMPERATURE_HOTSPOT_GCD = 50,
PMLOG_TEMPERATURE_HOTSPOT_MCD = 51,
PMLOG_THROTTLER_TEMP_EDGE_PERCENTAGE = 52,
PMLOG_THROTTLER_TEMP_HOTSPOT_PERCENTAGE = 53,
PMLOG_THROTTLER_TEMP_HOTSPOT_GCD_PERCENTAGE = 54,
PMLOG_THROTTLER_TEMP_HOTSPOT_MCD_PERCENTAGE = 55,
PMLOG_THROTTLER_TEMP_MEM_PERCENTAGE = 56,
PMLOG_THROTTLER_TEMP_VR_GFX_PERCENTAGE = 57,
PMLOG_THROTTLER_TEMP_VR_MEM0_PERCENTAGE = 58,
PMLOG_THROTTLER_TEMP_VR_MEM1_PERCENTAGE = 59,
PMLOG_THROTTLER_TEMP_VR_SOC_PERCENTAGE = 60,
PMLOG_THROTTLER_TEMP_LIQUID0_PERCENTAGE = 61,
PMLOG_THROTTLER_TEMP_LIQUID1_PERCENTAGE = 62,
PMLOG_THROTTLER_TEMP_PLX_PERCENTAGE = 63,
PMLOG_THROTTLER_TDC_GFX_PERCENTAGE = 64,
PMLOG_THROTTLER_TDC_SOC_PERCENTAGE = 65,
PMLOG_THROTTLER_TDC_USR_PERCENTAGE = 66,
PMLOG_THROTTLER_PPT0_PERCENTAGE = 67,
PMLOG_THROTTLER_PPT1_PERCENTAGE = 68,
PMLOG_THROTTLER_PPT2_PERCENTAGE = 69,
PMLOG_THROTTLER_PPT3_PERCENTAGE = 70,
PMLOG_THROTTLER_FIT_PERCENTAGE = 71,
PMLOG_THROTTLER_GFX_APCC_PLUS_PERCENTAGE = 72,
PMLOG_BOARD_POWER = 73,
PMLOG_THROTTLE_PERCENTAGE_TEMP_GFX = 52,
PMLOG_THROTTLE_PERCENTAGE_TEMP_MEM = 53,
PMLOG_THROTTLE_PERCENTAGE_TEMP_VR = 54,
PMLOG_THROTTLE_PERCENTAGE_POWER = 55,
PMLOG_THROTTLE_PERCENTAGE_TDC = 56,
PMLOG_THROTTLE_PERCENTAGE_VMAX = 57,
PMLOG_BUS_CURR_MAX_SPEED = 58,
PMLOG_RESERVED_1 = 59, //Currently Unused
PMLOG_RESERVED_2 = 60, //Currently Unused
PMLOG_RESERVED_3 = 61, //Currently Unused
PMLOG_RESERVED_4 = 62, //Currently Unused
PMLOG_RESERVED_5 = 63, //Currently Unused
PMLOG_RESERVED_6 = 64, //Currently Unused
PMLOG_RESERVED_7 = 65, //Currently Unused
PMLOG_RESERVED_8 = 66, //Currently Unused
PMLOG_RESERVED_9 = 67, //Currently Unused
PMLOG_RESERVED_10 = 68, //Currently Unused
PMLOG_RESERVED_11 = 69, //Currently Unused
PMLOG_RESERVED_12 = 70, //Currently Unused
PMLOG_RESERVED_13 = 71, //Currently Unused
PMLOG_RESERVED_14 = 72,
PMLOG_BOARD_POWER = 73,
PMLOG_MAX_SENSORS_REAL
} ADLSensorType;
@@ -2068,28 +2104,29 @@ typedef enum ADL_PMLOG_SENSORS
ADL_PMLOG_SSDGPU_POWERLIMIT = 49, // DGPU Power limit
ADL_PMLOG_TEMPERATURE_HOTSPOT_GCD = 50,
ADL_PMLOG_TEMPERATURE_HOTSPOT_MCD = 51,
ADL_PMLOG_THROTTLER_TEMP_EDGE_PERCENTAGE = 52,
ADL_PMLOG_THROTTLER_TEMP_HOTSPOT_PERCENTAGE = 53,
ADL_PMLOG_THROTTLER_TEMP_HOTSPOT_GCD_PERCENTAGE = 54,
ADL_PMLOG_THROTTLER_TEMP_HOTSPOT_MCD_PERCENTAGE = 55,
ADL_PMLOG_THROTTLER_TEMP_MEM_PERCENTAGE = 56,
ADL_PMLOG_THROTTLER_TEMP_VR_GFX_PERCENTAGE = 57,
ADL_PMLOG_THROTTLER_TEMP_VR_MEM0_PERCENTAGE = 58,
ADL_PMLOG_THROTTLER_TEMP_VR_MEM1_PERCENTAGE = 59,
ADL_PMLOG_THROTTLER_TEMP_VR_SOC_PERCENTAGE = 60,
ADL_PMLOG_THROTTLER_TEMP_LIQUID0_PERCENTAGE = 61,
ADL_PMLOG_THROTTLER_TEMP_LIQUID1_PERCENTAGE = 62,
ADL_PMLOG_THROTTLER_TEMP_PLX_PERCENTAGE = 63,
ADL_PMLOG_THROTTLER_TDC_GFX_PERCENTAGE = 64,
ADL_PMLOG_THROTTLER_TDC_SOC_PERCENTAGE = 65,
ADL_PMLOG_THROTTLER_TDC_USR_PERCENTAGE = 66,
ADL_PMLOG_THROTTLER_PPT0_PERCENTAGE = 67,
ADL_PMLOG_THROTTLER_PPT1_PERCENTAGE = 68,
ADL_PMLOG_THROTTLER_PPT2_PERCENTAGE = 69,
ADL_PMLOG_THROTTLER_PPT3_PERCENTAGE = 70,
ADL_PMLOG_THROTTLER_FIT_PERCENTAGE = 71,
ADL_PMLOG_THROTTLER_GFX_APCC_PLUS_PERCENTAGE = 72,
ADL_PMLOG_BOARD_POWER = 73,
ADL_PMLOG_THROTTLE_PERCENTAGE_TEMP_GFX = 52,
ADL_PMLOG_THROTTLE_PERCENTAGE_TEMP_MEM = 53,
ADL_PMLOG_THROTTLE_PERCENTAGE_TEMP_VR = 54,
ADL_PMLOG_THROTTLE_PERCENTAGE_POWER = 55,
ADL_PMLOG_THROTTLE_PERCENTAGE_TDC = 56,
ADL_PMLOG_THROTTLE_PERCENTAGE_VMAX = 57,
ADL_PMLOG_BUS_CURR_MAX_SPEED = 58,
ADL_PMLOG_RESERVED_1 = 59, //Currently Unused
ADL_PMLOG_RESERVED_2 = 60, //Currently Unused
ADL_PMLOG_RESERVED_3 = 61, //Currently Unused
ADL_PMLOG_RESERVED_4 = 62, //Currently Unused
ADL_PMLOG_RESERVED_5 = 63, //Currently Unused
ADL_PMLOG_RESERVED_6 = 64, //Currently Unused
ADL_PMLOG_RESERVED_7 = 65, //Currently Unused
ADL_PMLOG_RESERVED_8 = 66, //Currently Unused
ADL_PMLOG_RESERVED_9 = 67, //Currently Unused
ADL_PMLOG_RESERVED_10 = 68, //Currently Unused
ADL_PMLOG_RESERVED_11 = 69, //Currently Unused
ADL_PMLOG_RESERVED_12 = 70, //Currently Unused
ADL_PMLOG_CLK_NPUCLK = 71, //NPU frequency
ADL_PMLOG_NPU_BUSY_AVG = 72, //NPU busy
ADL_PMLOG_BOARD_POWER = 73,
ADL_PMLOG_TEMPERATURE_INTAKE = 74,
ADL_PMLOG_MAX_SENSORS_REAL
} ADL_PMLOG_SENSORS;
@@ -2393,6 +2430,9 @@ typedef enum ADL_PMLOG_SENSORS
/// Indicates there is crossGPU clone
#define ADL_CROSSGPUDISPLAYCLONE 0x2
/// @}
/// @}
/// \defgroup define_D3DKMT_HANDLE
@@ -2493,7 +2533,11 @@ typedef enum ADL_UIFEATURES_GROUP
ADL_UIFEATURES_GROUP_PROVSR = 12,
ADL_UIFEATURES_GROUP_SMA = 13,
ADL_UIFEATURES_GROUP_CAMERA = 14,
ADL_UIFEATURES_GROUP_FRTCPRO = 15
ADL_UIFEATURES_GROUP_FRTCPRO = 15,
ADL_UIFEATURES_GROUP_DELAGNEXT = 16,
ADL_UIFEATURES_GROUP_RTBOOST = 17,
ADL_UIFEATURES_GROUP_UAI = 18
} ADL_UIFEATURES_GROUP;
@@ -2587,9 +2631,18 @@ typedef enum ADL_USER_SETTINGS
ADL_USER_SETTINGS_USU_PROFILE = 1 << 4, //notify USU settings change
ADL_USER_SETTINGS_CVDC_PROFILE = 1 << 5, //notify Color Vision Deficiency Corretion settings change
ADL_USER_SETTINGS_SCE_PROFILE = 1 << 6,
ADL_USER_SETTINGS_PROVSR = 1 << 7
ADL_USER_SETTINGS_PROVSR = 1 << 7,
ADL_USER_SETTINGS_RTBOOST_PROFILE=1 << 8,
ADL_USER_SETTINGS_USU2_PROFILE = 1 << 9, //notify USU2 settings change
} ADL_USER_SETTINGS;
//FRAME_TIMESTAMPS_SHARED_MEMORY type
typedef enum FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE
{
FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE_UNKNOWN = 0,
FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE_LEGACY,
FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE_INDEXED
}FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE;
#define ADL_REG_DEVICE_FUNCTION_1 0x00000001
#endif /* ADL_DEFINES_H_ */
+2 -6
View File
@@ -33,14 +33,10 @@
#include "adl_structures.h"
#if defined (LINUX)
#define __stdcall
#endif /* (LINUX) */
/// Memory Allocation Call back
typedef void* ( __stdcall *ADL_MAIN_MALLOC_CALLBACK )( int );
#define ADL_SDK_MAJOR_VERSION 17
#define ADL_SDK_MINOR_VERSION 1
#define ADL_SDK_MAJOR_VERSION 18
#define ADL_SDK_MINOR_VERSION 0
#endif /* ADL_SDK_H_ */
+29 -36
View File
@@ -21,7 +21,7 @@
// SOFTWARE.
/// \file adl_structures.h
///\brief This file contains the structure declarations that are used by the public ADL interfaces for \ALL platforms.\n <b>Included in ADL SDK</b>
///\brief This file contains the structure declarations that are used by the public ADL interfaces for \WIN platforms.\n <b>Included in ADL SDK</b>
///
/// All data structures used in AMD Display Library (ADL) public interfaces should be defined in this header file.
///
@@ -41,7 +41,7 @@
////////////////////////////////////////////////////////////////////////////////////////////
typedef struct AdapterInfo
{
/// \ALL_STRUCT_MEM
/// \WIN_STRUCT_MEM
/// Size of the structure.
int iSize;
@@ -59,7 +59,7 @@ typedef struct AdapterInfo
int iVendorID;
/// Adapter name.
char strAdapterName[ADL_MAX_PATH];
/// Display name. For example, "\\\\Display0" for Windows or ":0:0" for Linux.
/// Display name. For example, "\\\\Display0" for Windows.
char strDisplayName[ADL_MAX_PATH];
/// Present or not; 1 if present and 0 if not present.It the logical adapter is present, the display name such as \\\\.\\Display1 can be found from OS
int iPresent;
@@ -80,38 +80,8 @@ typedef struct AdapterInfo
#endif /* (_WIN32) || (_WIN64) */
#if defined (LINUX)
/// \LNX_STRUCT_MEM
/// Internal X screen number from GPUMapInfo (DEPRICATED use XScreenInfo)
int iXScreenNum;
/// Internal driver index from GPUMapInfo
int iDrvIndex;
/// \deprecated Internal x config file screen identifier name. Use XScreenInfo instead.
char strXScreenConfigName[ADL_MAX_PATH];
#endif /* (LINUX) */
} AdapterInfo, *LPAdapterInfo;
/////////////////////////////////////////////////////////////////////////////////////////////
///\brief Structure containing information about the Linux X screen information.
///
/// This structure is used to store the current screen number and xorg.conf ID name assoicated with an adapter index.
/// This structure is updated during ADL_Main_Control_Refresh or ADL_ScreenInfo_Update.
/// Note: This structure should be used in place of iXScreenNum and strXScreenConfigName in AdapterInfo as they will be
/// deprecated.
/// \nosubgrouping
////////////////////////////////////////////////////////////////////////////////////////////
#if defined (LINUX)
typedef struct XScreenInfo
{
/// Internal X screen number from GPUMapInfo.
int iXScreenNum;
/// Internal x config file screen identifier name.
char strXScreenConfigName[ADL_MAX_PATH];
} XScreenInfo, *LPXScreenInfo;
#endif /* (LINUX) */
/////////////////////////////////////////////////////////////////////////////////////////////
///\brief Structure containing information about an controller mode
///
@@ -453,8 +423,12 @@ typedef struct ADLDDCInfo2
int ulMaxBacklightMinLuminanceData;
int ulMinBacklightMinLuminanceData;
// Display screen width/height
int ulScreenWidth;
int ulScreenHeight;
// Reserved for future use
int iReserved[4];
int iReserved[2];
} ADLDDCInfo2, *LPADLDDCInfo2;
/////////////////////////////////////////////////////////////////////////////////////////////
@@ -3614,6 +3588,23 @@ typedef struct ADL_BOOST_SETTINGS
int GlobalMinRes_Step; //Gloabl Min Resolution step value
}ADL_BOOST_SETTINGS;
/////////////////////////////////////////////////////////////////////////////////////////////
///\brief Structure containing information about BOOST Settings
///
/// Elements of BOOST settings.
/// \nosubgrouping
////////////////////////////////////////////////////////////////////////////////////////////
typedef struct ADL_BOOST_SETTINGSX2
{
int Hotkey; // Hotkey value
int GlobalEnable; //Global enable value
int GlobalMinRes; //Gloabl Min Resolution value
int GlobalMinRes_MinLimit; //Gloabl Min Resolution slider min limit value
int GlobalMinRes_MaxLimit; //Gloabl Min Resolution slider max limit value
int GlobalMinRes_Step; //Gloabl Min Resolution step value
int VsrSupported; //Allows for interop with Upscaling/RSR
}ADL_BOOST_SETTINGSX2;
/////////////////////////////////////////////////////////////////////////////////////////////
///\brief Structure containing information about ProVSR Settings change reason
@@ -3817,7 +3808,7 @@ typedef struct ADL_RADEON_LED_PATTERN_CONFIG
////////////////////////////////////////////////////////////////////////////////////////////
typedef struct AdapterInfoX2
{
/// \ALL_STRUCT_MEM
/// \WIN_STRUCT_MEM
/// Size of the structure.
int iSize;
@@ -4164,6 +4155,7 @@ typedef struct ADLHDCPSettings
///
/// This structure is used to store the Mantle Driver information
/// \nosubgrouping
/// \deprecated This structure has been deprecated.
////////////////////////////////////////////////////////////////////////////////////////////
typedef struct ADLMantleAppInfo
@@ -4286,4 +4278,5 @@ typedef struct ADLSmartShiftSettings
int iCurrentValue;
int iFlags; //refer to define_smartshift_bits
}ADLSmartShiftSettings, *LPADLSmartShiftSettings;
#endif /* ADL_STRUCTURES_H_ */
#endif /* ADL_STRUCTURES_H_ */
+1 -1
View File
@@ -1,6 +1,6 @@
{
"home": "https://github.com/GPUOpen-LibrariesAndSDKs/display-library",
"license": "MIT (embeded in source)",
"version": "ADL SDK 17.1",
"version": "ADL SDK 18.1",
"author": "Advanced Micro Devices, Inc"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"home": "https://github.com/ibireme/yyjson",
"license": "MIT ( embed in source )",
"version": "0.12.0",
"version": "0.13.0",
"author": "ibireme"
}
+700 -285
View File
File diff suppressed because it is too large Load Diff
+911 -674
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -31,6 +31,10 @@ typedef struct FFPlatform {
FFstrbuf userShell;
FFPlatformSysinfo sysinfo;
#if _WIN32
uint32_t initCP; // The code page used by the console when the program started
#endif
} FFPlatform;
void ffPlatformInit(FFPlatform* platform);
+42 -17
View File
@@ -1,11 +1,10 @@
#pragma once
#include "common/attributes.h"
#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#define FF_LIST_DEFAULT_ALLOC 16
@@ -15,43 +14,41 @@ typedef struct FFlist {
uint32_t capacity;
} FFlist;
void* ffListAdd(FFlist* list, uint32_t elementSize);
// Removes the first element, and copy its value to `*result`
bool ffListShift(FFlist* list, uint32_t elementSize, void* result);
bool ffListShift(FFlist* list, uint32_t elementSize, void* __restrict result);
// Removes the last element, and copy its value to `*result`
bool ffListPop(FFlist* list, uint32_t elementSize, void* result);
bool ffListPop(FFlist* list, uint32_t elementSize, void* __restrict result);
static inline void ffListInit(FFlist* list) {
list->capacity = 0;
list->length = 0;
list->data = NULL;
list->data = nullptr;
}
static inline void ffListInitA(FFlist* list, uint32_t elementSize, uint32_t capacity) {
ffListInit(list);
list->capacity = capacity;
list->data = __builtin_expect(capacity == 0, 0) ? NULL : (uint8_t*) malloc((size_t) capacity * elementSize);
list->data = __builtin_expect(capacity == 0, 0) ? nullptr : (uint8_t*) malloc((size_t) capacity * elementSize);
}
FF_A_NODISCARD static inline FFlist ffListCreate() {
[[nodiscard]] static inline FFlist ffListCreate() {
FFlist result;
ffListInit(&result);
return result;
}
FF_A_NODISCARD static inline FFlist ffListCreateA(uint32_t elementSize, uint32_t capacity) {
[[nodiscard]] static inline FFlist ffListCreateA(uint32_t elementSize, uint32_t capacity) {
FFlist result;
ffListInitA(&result, elementSize, capacity);
return result;
}
FF_A_NODISCARD static inline void* ffListGet(const FFlist* list, uint32_t elementSize, uint32_t index) {
[[nodiscard]] static inline void* ffListGet(const FFlist* list, uint32_t elementSize, uint32_t index) {
assert(list->capacity > index);
return list->data + (index * elementSize);
}
FF_A_NODISCARD static inline uint32_t ffListFirstIndexComp(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
[[nodiscard]] static inline uint32_t ffListFirstIndexComp(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
for (uint32_t i = 0; i < list->length; i++) {
if (compFunc(ffListGet(list, elementSize, i), compElement)) {
return i;
@@ -61,7 +58,7 @@ FF_A_NODISCARD static inline uint32_t ffListFirstIndexComp(const FFlist* list, u
return list->length;
}
FF_A_NODISCARD static inline bool ffListContains(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
[[nodiscard]] static inline bool ffListContains(const FFlist* list, uint32_t elementSize, void* compElement, bool (*compFunc)(const void*, const void*)) {
return ffListFirstIndexComp(list, elementSize, compElement, compFunc) != list->length;
}
@@ -89,7 +86,7 @@ static inline void ffListDestroy(FFlist* list) {
// Avoid free-after-use. These 3 assignments are cheap so don't remove them
list->capacity = list->length = 0;
free(list->data);
list->data = NULL;
list->data = nullptr;
}
static inline void ffListClear(FFlist* list) {
@@ -105,12 +102,34 @@ static inline void ffListReserve(FFlist* list, uint32_t elementSize, uint32_t ne
list->capacity = newCapacity;
}
static inline void* ffListAdd(FFlist* list, uint32_t elementSize) {
if (__builtin_expect(list->length == list->capacity, false)) {
ffListReserve(list, elementSize, list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2);
}
++list->length;
return ffListGet(list, elementSize, list->length - 1);
}
static inline void ffListRemoveAt(FFlist* list, uint32_t elementSize, uint32_t index) {
assert(list->length > index);
memmove(list->data + (index * elementSize), list->data + ((index + 1) * elementSize), (size_t) (list->length - index - 1) * elementSize);
--list->length;
}
static inline void ffListInsertAt(FFlist* list, uint32_t elementSize, uint32_t index, const void* element) {
assert(list->length >= index);
ffListAdd(list, elementSize);
memmove(list->data + ((index + 1) * elementSize), list->data + (index * elementSize), (size_t) (list->length - index - 1) * elementSize);
memcpy(list->data + (index * elementSize), element, elementSize);
}
#define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
for (itemType* itemVarName = (itemType*) (listVar).data; \
itemVarName - (itemType*) (listVar).data < (intptr_t) (listVar).length; \
++itemVarName)
#define FF_LIST_AUTO_DESTROY FFlist FF_A_CLEANUP(ffListDestroy)
#define FF_LIST_AUTO_DESTROY [[gnu::cleanup(ffListDestroy)]] FFlist
#define FF_LIST_GET(itemType, listVar, index) \
({ \
@@ -120,6 +139,12 @@ static inline void ffListReserve(FFlist* list, uint32_t elementSize, uint32_t ne
#define FF_LIST_ADD(itemType, listVar) (itemType*) ffListAdd(&(listVar), (uint32_t) sizeof(itemType))
#define FF_LIST_REMOVE_AT(itemType, listVar, index) \
ffListRemoveAt(&(listVar), (uint32_t) sizeof(itemType), (index))
#define FF_LIST_INSERT_AT(itemType, listVar, index, pElement) \
ffListInsertAt(&(listVar), (uint32_t) sizeof(itemType), (index), (pElement))
#define FF_LIST_FIRST(itemType, listVar) FF_LIST_GET(itemType, listVar, 0)
#define FF_LIST_LAST(itemType, listVar) \
({ \
@@ -129,9 +154,9 @@ static inline void ffListReserve(FFlist* list, uint32_t elementSize, uint32_t ne
#define FF_LIST_CONTAINS(listVar, pCompElement, compFunc) \
({ \
typedef __typeof__(*(pCompElement)) compElementType; \
typedef typeof(*(pCompElement)) compElementType; \
typedef bool compFuncType(const compElementType*, const compElementType*); \
static_assert(__builtin_types_compatible_p(__typeof__(compFunc), compFuncType), "Incompatible callback function"); \
static_assert(__builtin_types_compatible_p(typeof(compFunc), compFuncType), "Incompatible callback function"); \
ffListContains(&(listVar), (uint32_t) sizeof(*(pCompElement)), (pCompElement), (bool (*)(const void*, const void*)) compFunc); \
})
+175 -110
View File
@@ -1,7 +1,5 @@
#pragma once
#include "common/attributes.h"
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -9,6 +7,8 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "common/memrchr.h"
#include "common/arrutil.h"
#ifdef FF_USE_SYSTEM_YYJSON
#include <yyjson.h>
@@ -36,18 +36,15 @@ 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);
[[gnu::format(printf, 2, 3)]] void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...);
[[gnu::format(printf, 1, 2)]] [[nodiscard]] FFstrbuf ffStrbufCreateF(const char* format, ...);
void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free);
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free);
void ffStrbufClear(FFstrbuf* strbuf);
void ffStrbufEnsureFreeNoCheck(FFstrbuf* strbuf, uint32_t free);
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value);
void ffStrbufAppendC(FFstrbuf* strbuf, char c);
void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c);
void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value);
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int (*transformFunc)(int));
FF_A_PRINTF(2, 3) void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
[[gnu::format(printf, 2, 3)]] void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments);
const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until);
@@ -60,7 +57,7 @@ void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c);
// 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_A_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
[[gnu::format(printf, 2, 3)]] void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
void ffStrbufTrimRight(FFstrbuf* strbuf, char c);
@@ -71,11 +68,6 @@ bool ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endInd
void ffStrbufRemoveS(FFstrbuf* strbuf, const char* str);
void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, const char* strings[]);
FF_A_NODISCARD uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c);
FF_A_NODISCARD uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str);
FF_A_NODISCARD uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c);
void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace);
// Returns true if the strbuf is modified
@@ -86,25 +78,18 @@ bool ffStrbufSubstrAfterFirstS(FFstrbuf* strbuf, const char* str);
bool ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c);
bool ffStrbufSubstr(FFstrbuf* strbuf, uint32_t start, uint32_t end);
FF_A_NODISCARD uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c);
[[nodiscard]] uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c);
bool ffStrbufRemoveIgnCaseEndS(FFstrbuf* strbuf, const char* end);
bool ffStrbufEnsureEndsWithC(FFstrbuf* strbuf, char c);
void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file);
void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file);
FF_A_NODISCARD double ffStrbufToDouble(const FFstrbuf* strbuf, double defaultValue);
FF_A_NODISCARD int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue);
FF_A_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue);
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
// `lineptr` must be `nullptr` 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);
@@ -117,7 +102,7 @@ void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf
* @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line
(points to buffer's internal memory address to avoid memory allocation and copy).
MUST NOT be freed by the caller, unlike `getline(3)`.
* MUST be NULL for the first call.
* MUST be nullptr for the first call.
* @param[in,out] n The pointer to the size of the buffer of lineptr.
MUST be 0 for the first call.
* @param[in] buffer The buffer to read from.
@@ -149,7 +134,7 @@ void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value);
// if `precision < 0`, let yyjson decide the precision
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros);
FF_A_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) {
[[nodiscard]] static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) {
FFstrbuf strbuf;
ffStrbufInitA(&strbuf, allocate);
return strbuf;
@@ -164,7 +149,7 @@ static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf*
}
}
FF_A_NODISCARD static inline FFstrbuf ffStrbufCreateCopy(const FFstrbuf* src) {
[[nodiscard]] static inline FFstrbuf ffStrbufCreateCopy(const FFstrbuf* src) {
FFstrbuf strbuf;
ffStrbufInitCopy(&strbuf, src);
return strbuf;
@@ -180,37 +165,12 @@ static inline void ffStrbufInitMove(FFstrbuf* strbuf, FFstrbuf* src) {
}
}
FF_A_NODISCARD static inline FFstrbuf ffStrbufCreateMove(FFstrbuf* src) {
[[nodiscard]] static inline FFstrbuf ffStrbufCreateMove(FFstrbuf* src) {
FFstrbuf strbuf;
ffStrbufInitMove(&strbuf, src);
return strbuf;
}
FF_A_NODISCARD static inline FFstrbuf ffStrbufCreateVF(const char* format, va_list arguments) {
FFstrbuf strbuf;
ffStrbufInitVF(&strbuf, format, arguments);
return strbuf;
}
FF_A_PRINTF(2, 3) static inline void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...) {
va_list arguments;
va_start(arguments, format);
ffStrbufInitVF(strbuf, format, arguments);
va_end(arguments);
}
FF_A_PRINTF(1, 2) FF_A_NODISCARD static inline FFstrbuf
ffStrbufCreateF(const char* format, ...) {
FFstrbuf strbuf;
va_list arguments;
va_start(arguments, format);
ffStrbufInitVF(&strbuf, format, arguments);
va_end(arguments);
return strbuf;
}
static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr) {
ffStrbufInitMoveNS(strbuf, (uint32_t) strlen(heapStr), heapStr);
}
@@ -224,8 +184,8 @@ static inline void ffStrbufDestroy(FFstrbuf* strbuf) {
ffStrbufInit(strbuf);
}
FF_A_NODISCARD static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf) {
assert(strbuf != NULL);
[[nodiscard]] static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf) {
assert(strbuf != nullptr);
if (strbuf->allocated == 0) {
return 0;
}
@@ -233,14 +193,78 @@ FF_A_NODISCARD static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf) {
return strbuf->allocated - strbuf->length - 1; // - 1 for the null byte
}
static inline void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) {
if (__builtin_expect(free == 0, false)) {
if (__builtin_expect(!(strbuf->allocated == 0 && strbuf->length > 0), true)) {
return;
}
} else {
if (__builtin_expect(ffStrbufGetFree(strbuf) >= free, true)) {
return;
}
}
ffStrbufEnsureFreeNoCheck(strbuf, free);
}
static inline void ffStrbufClear(FFstrbuf* strbuf) {
assert(strbuf != nullptr);
extern char* CHAR_NULL_PTR;
if (strbuf->allocated == 0) {
strbuf->chars = CHAR_NULL_PTR;
} else {
strbuf->chars[0] = '\0';
}
strbuf->length = 0;
}
static inline void ffStrbufAppendC(FFstrbuf* strbuf, char c) {
ffStrbufEnsureFree(strbuf, 1);
strbuf->chars[strbuf->length++] = c;
strbuf->chars[strbuf->length] = '\0';
}
static inline void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c) {
if (__builtin_expect(num == 0, false)) {
return;
}
ffStrbufEnsureFree(strbuf, num);
memset(&strbuf->chars[strbuf->length], c, num);
strbuf->length += num;
strbuf->chars[strbuf->length] = '\0';
}
static inline void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
if (__builtin_expect(value == nullptr || length == 0, false)) {
return;
}
ffStrbufEnsureFree(strbuf, length);
memcpy(&strbuf->chars[strbuf->length], value, length);
strbuf->length += length;
strbuf->chars[strbuf->length] = '\0';
}
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value) {
assert(value != strbuf);
if (value == nullptr) {
return;
}
ffStrbufAppendNS(strbuf, value->length, value->chars);
}
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);
assert(strbuf != nullptr);
if (value == NULL) {
if (value == nullptr) {
ffStrbufClear(strbuf);
} else {
ffStrbufSetNS(strbuf, (uint32_t) strlen(value), value);
@@ -248,7 +272,7 @@ static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value) {
}
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
assert(strbuf != NULL);
assert(strbuf != nullptr);
if (yyjson_is_str(jsonVal)) {
ffStrbufSetNS(strbuf, (uint32_t) unsafe_yyjson_get_len(jsonVal), unsafe_yyjson_get_str(jsonVal));
@@ -260,7 +284,7 @@ static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal) {
}
static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value) {
if (value == NULL) {
if (value == nullptr) {
return;
}
ffStrbufAppendNS(strbuf, (uint32_t) strlen(value), value);
@@ -280,7 +304,7 @@ static inline void ffStrbufInit(FFstrbuf* strbuf) {
strbuf->chars = CHAR_NULL_PTR;
}
FF_A_NODISCARD static inline FFstrbuf ffStrbufCreate(void) {
[[nodiscard]] static inline FFstrbuf ffStrbufCreate(void) {
FFstrbuf strbuf;
ffStrbufInit(&strbuf);
return strbuf;
@@ -297,7 +321,7 @@ static inline void ffStrbufInitStatic(FFstrbuf* strbuf, const char* str) {
strbuf->chars = (char*) str;
}
FF_A_NODISCARD static inline FFstrbuf ffStrbufCreateStatic(const char* str) {
[[nodiscard]] static inline FFstrbuf ffStrbufCreateStatic(const char* str) {
FFstrbuf strbuf;
ffStrbufInitStatic(&strbuf, str);
return strbuf;
@@ -308,7 +332,7 @@ static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value) {
free(strbuf->chars);
}
if (value != NULL) {
if (value != nullptr) {
ffStrbufInitStatic(strbuf, value);
} else {
ffStrbufInit(strbuf);
@@ -320,7 +344,7 @@ static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char*
ffStrbufAppendNS(strbuf, length, str);
}
FF_A_NODISCARD static inline FFstrbuf ffStrbufCreateNS(uint32_t length, const char* str) {
[[nodiscard]] static inline FFstrbuf ffStrbufCreateNS(uint32_t length, const char* str) {
FFstrbuf strbuf;
ffStrbufInitNS(&strbuf, length, str);
return strbuf;
@@ -336,100 +360,113 @@ static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str) {
ffStrbufAppendS(strbuf, str);
}
FF_A_NODISCARD static inline FFstrbuf ffStrbufCreateS(const char* str) {
[[nodiscard]] static inline FFstrbuf ffStrbufCreateS(const char* str) {
FFstrbuf strbuf;
ffStrbufInitS(&strbuf, str);
return strbuf;
}
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value) {
assert(value != strbuf);
if (value == NULL) {
return;
}
ffStrbufAppendNS(strbuf, value->length, value->chars);
}
static inline void ffStrbufPrepend(FFstrbuf* strbuf, FFstrbuf* value) {
if (value == NULL) {
if (value == nullptr) {
return;
}
ffStrbufPrependNS(strbuf, value->length, value->chars);
}
static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value) {
if (value == NULL) {
if (value == nullptr) {
return;
}
ffStrbufPrependNS(strbuf, (uint32_t) strlen(value), value);
}
static inline FF_A_NODISCARD int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp) {
[[nodiscard]] static inline 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);
}
static inline FF_A_NODISCARD bool ffStrbufEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
[[nodiscard]] static inline bool ffStrbufEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
return ffStrbufComp(strbuf, comp) == 0;
}
static inline FF_A_NODISCARD int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp) {
[[nodiscard]] static inline int ffStrbufCompS(const FFstrbuf* strbuf, const char* comp) {
return strcmp(strbuf->chars, comp);
}
static inline FF_A_NODISCARD bool ffStrbufEqualS(const FFstrbuf* strbuf, const char* comp) {
[[nodiscard]] static inline bool ffStrbufEqualS(const FFstrbuf* strbuf, const char* comp) {
return ffStrbufCompS(strbuf, comp) == 0;
}
static inline FF_A_NODISCARD int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp) {
[[nodiscard]] static inline int ffStrbufIgnCaseCompS(const FFstrbuf* strbuf, const char* comp) {
return strcasecmp(strbuf->chars, comp);
}
static inline FF_A_NODISCARD bool ffStrbufIgnCaseEqualS(const FFstrbuf* strbuf, const char* comp) {
[[nodiscard]] static inline bool ffStrbufIgnCaseEqualS(const FFstrbuf* strbuf, const char* comp) {
return ffStrbufIgnCaseCompS(strbuf, comp) == 0;
}
static inline FF_A_NODISCARD int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp) {
[[nodiscard]] static inline int ffStrbufIgnCaseComp(const FFstrbuf* strbuf, const FFstrbuf* comp) {
return ffStrbufIgnCaseCompS(strbuf, comp->chars);
}
static inline FF_A_NODISCARD bool ffStrbufIgnCaseEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
[[nodiscard]] static inline bool ffStrbufIgnCaseEqual(const FFstrbuf* strbuf, const FFstrbuf* comp) {
return ffStrbufIgnCaseComp(strbuf, comp) == 0;
}
static inline FF_A_NODISCARD bool ffStrbufContainC(const FFstrbuf* strbuf, char c) {
return memchr(strbuf->chars, c, strbuf->length) != NULL;
[[nodiscard]] static inline bool ffStrbufContainC(const FFstrbuf* strbuf, char c) {
return memchr(strbuf->chars, c, strbuf->length) != nullptr;
}
static inline FF_A_NODISCARD bool ffStrbufContainS(const FFstrbuf* strbuf, const char* str) {
return strstr(strbuf->chars, str) != NULL;
[[nodiscard]] static inline bool ffStrbufContainS(const FFstrbuf* strbuf, const char* str) {
return strstr(strbuf->chars, str) != nullptr;
}
static inline FF_A_NODISCARD bool ffStrbufContain(const FFstrbuf* strbuf, const FFstrbuf* str) {
[[nodiscard]] static inline bool ffStrbufContain(const FFstrbuf* strbuf, const FFstrbuf* str) {
return ffStrbufContainS(strbuf, str->chars);
}
static inline FF_A_NODISCARD bool ffStrbufContainIgnCaseS(const FFstrbuf* strbuf, const char* str) {
return strcasestr(strbuf->chars, str) != NULL;
[[nodiscard]] static inline bool ffStrbufContainIgnCaseS(const FFstrbuf* strbuf, const char* str) {
return strcasestr(strbuf->chars, str) != nullptr;
}
static inline FF_A_NODISCARD bool ffStrbufContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* str) {
[[nodiscard]] static inline bool ffStrbufContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* str) {
return ffStrbufContainIgnCaseS(strbuf, str->chars);
}
static inline FF_A_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) {
[[nodiscard]] static inline uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
assert(start <= strbuf->length);
const char* ptr = (const char*) memchr(strbuf->chars + start, c, strbuf->length - start);
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
}
[[nodiscard]] static inline uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) {
assert(start <= strbuf->length);
const char* ptr = strstr(strbuf->chars + start, str);
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
}
[[nodiscard]] static inline uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
assert(start <= strbuf->length);
const char* ptr = (const char*) memrchr(strbuf->chars, c, start + 1);
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
}
[[nodiscard]] static inline uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) {
return ffStrbufNextIndexC(strbuf, 0, c);
}
static inline FF_A_NODISCARD uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched) {
[[nodiscard]] static inline uint32_t ffStrbufFirstIndex(const FFstrbuf* strbuf, const FFstrbuf* searched) {
return ffStrbufNextIndexS(strbuf, 0, searched->chars);
}
static inline FF_A_NODISCARD uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str) {
[[nodiscard]] static inline uint32_t ffStrbufFirstIndexS(const FFstrbuf* strbuf, const char* str) {
return ffStrbufNextIndexS(strbuf, 0, str);
}
static inline FF_A_NODISCARD uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c) {
[[nodiscard]] static inline uint32_t ffStrbufLastIndexC(const FFstrbuf* strbuf, char c) {
if (strbuf->length == 0) {
return 0;
}
@@ -445,11 +482,11 @@ static inline bool ffStrbufSubstrBeforeLastC(FFstrbuf* strbuf, char c) {
return ffStrbufSubstrBefore(strbuf, ffStrbufLastIndexC(strbuf, c));
}
static inline FF_A_NODISCARD bool ffStrbufStartsWithC(const FFstrbuf* strbuf, char c) {
[[nodiscard]] static inline bool ffStrbufStartsWithC(const FFstrbuf* strbuf, char c) {
return strbuf->chars[0] == c;
}
static inline FF_A_NODISCARD bool ffStrbufStartsWithSN(const FFstrbuf* strbuf, const char* start, uint32_t length) {
[[nodiscard]] static inline bool ffStrbufStartsWithSN(const FFstrbuf* strbuf, const char* start, uint32_t length) {
if (length > strbuf->length) {
return false;
}
@@ -457,34 +494,34 @@ static inline FF_A_NODISCARD bool ffStrbufStartsWithSN(const FFstrbuf* strbuf, c
return memcmp(strbuf->chars, start, length) == 0;
}
static inline FF_A_NODISCARD bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start) {
[[nodiscard]] static inline bool ffStrbufStartsWithS(const FFstrbuf* strbuf, const char* start) {
return ffStrbufStartsWithSN(strbuf, start, (uint32_t) strlen(start));
}
static inline FF_A_NODISCARD bool ffStrbufStartsWith(const FFstrbuf* strbuf, const FFstrbuf* start) {
[[nodiscard]] static inline bool ffStrbufStartsWith(const FFstrbuf* strbuf, const FFstrbuf* start) {
return ffStrbufStartsWithSN(strbuf, start->chars, start->length);
}
static inline FF_A_NODISCARD bool ffStrbufStartsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t length, const char* start) {
[[nodiscard]] static inline bool ffStrbufStartsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t length, const char* start) {
if (length > strbuf->length) {
return false;
}
return strncasecmp(strbuf->chars, start, length) == 0;
}
static inline FF_A_NODISCARD bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) {
[[nodiscard]] static inline bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start) {
return ffStrbufStartsWithIgnCaseNS(strbuf, (uint32_t) strlen(start), start);
}
static inline FF_A_NODISCARD bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) {
[[nodiscard]] static inline bool ffStrbufStartsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* start) {
return ffStrbufStartsWithIgnCaseNS(strbuf, start->length, start->chars);
}
static inline FF_A_NODISCARD bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c) {
[[nodiscard]] static inline bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c) {
return strbuf->length == 0 ? false : strbuf->chars[strbuf->length - 1] == c;
}
static inline FF_A_NODISCARD bool ffStrbufEndsWithNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
[[nodiscard]] static inline bool ffStrbufEndsWithNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
if (endLength > strbuf->length) {
return false;
}
@@ -492,30 +529,30 @@ static inline FF_A_NODISCARD bool ffStrbufEndsWithNS(const FFstrbuf* strbuf, uin
return memcmp(strbuf->chars + strbuf->length - endLength, end, endLength) == 0;
}
static inline FF_A_NODISCARD bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end) {
[[nodiscard]] static inline bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end) {
return ffStrbufEndsWithNS(strbuf, (uint32_t) strlen(end), end);
}
static inline FF_A_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*const fn)(int)) {
[[nodiscard]] static inline bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*const fn)(int)) {
return strbuf->length == 0 ? false : fn(strbuf->chars[strbuf->length - 1]);
}
static inline FF_A_NODISCARD bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end) {
[[nodiscard]] static inline bool ffStrbufEndsWith(const FFstrbuf* strbuf, const FFstrbuf* end) {
return ffStrbufEndsWithNS(strbuf, end->length, end->chars);
}
static inline FF_A_NODISCARD bool ffStrbufEndsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
[[nodiscard]] static inline bool ffStrbufEndsWithIgnCaseNS(const FFstrbuf* strbuf, uint32_t endLength, const char* end) {
if (endLength > strbuf->length) {
return false;
}
return strcasecmp(strbuf->chars + strbuf->length - endLength, end) == 0;
}
static inline FF_A_NODISCARD bool ffStrbufEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end) {
[[nodiscard]] static inline bool ffStrbufEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end) {
return ffStrbufEndsWithIgnCaseNS(strbuf, (uint32_t) strlen(end), end);
}
static inline FF_A_NODISCARD bool ffStrbufEndsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* end) {
[[nodiscard]] static inline bool ffStrbufEndsWithIgnCase(const FFstrbuf* strbuf, const FFstrbuf* end) {
return ffStrbufEndsWithIgnCaseNS(strbuf, end->length, end->chars);
}
@@ -561,7 +598,35 @@ static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const
return ffStrbufSeparatedContainIgnCaseNS(strbuf, comp->length, comp->chars, separator);
}
static inline void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file) {
fwrite(strbuf->chars, sizeof(*strbuf->chars), strbuf->length, file);
}
static inline void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file) {
ffStrbufWriteTo(strbuf, file);
fputc('\n', file);
}
[[nodiscard]] static inline double ffStrbufToDouble(const FFstrbuf* strbuf, double defaultValue) {
char* str_end;
double result = strtod(strbuf->chars, &str_end);
return str_end == strbuf->chars ? defaultValue : result;
}
[[nodiscard]] static inline uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue) {
char* str_end;
unsigned long long result = strtoull(strbuf->chars, &str_end, 10);
return str_end == strbuf->chars ? defaultValue : (uint64_t) result;
}
[[nodiscard]] static inline int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue) {
char* str_end;
long long result = strtoll(strbuf->chars, &str_end, 10);
return str_end == strbuf->chars ? defaultValue : (int64_t) result;
}
// Returns true if the strbuf is modified
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf);
#define FF_STRBUF_AUTO_DESTROY FFstrbuf FF_A_CLEANUP(ffStrbufDestroy)
#define FF_STRBUF_AUTO_DESTROY [[gnu::cleanup(ffStrbufDestroy)]] FFstrbuf
#define FF_STRBUF_STATIC(str) { .allocated = 0, .length = (uint32_t) sizeof(str) - 1, .chars = str }
+65 -24
View File
@@ -5,13 +5,13 @@ const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result) {
if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberSInt64Type, result)) {
return "Number type is not SInt64";
}
return NULL;
return nullptr;
} else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
if (CFDataGetLength((CFDataRef) cf) != sizeof(int64_t)) {
return "Data length is not sizeof(int64_t)";
}
CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(int64_t)), (uint8_t*) result);
return NULL;
return nullptr;
}
return "TypeID is neither 'CFNumber' nor 'CFData'";
@@ -22,22 +22,45 @@ const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result) {
if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberSInt32Type, result)) {
return "Number type is not SInt32";
}
return NULL;
return nullptr;
} else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
if (CFDataGetLength((CFDataRef) cf) != sizeof(int)) {
return "Data length is not sizeof(int)";
if (CFDataGetLength((CFDataRef) cf) != sizeof(*result)) {
return "Data length is not sizeof(int32_t)";
}
CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(int)), (uint8_t*) result);
return NULL;
CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(*result)), (uint8_t*) result);
return nullptr;
}
return "TypeID is neither 'CFNumber' nor 'CFData'";
}
const char* ffCfNumGetDouble(CFTypeRef cf, double* result) {
if (CFGetTypeID(cf) == CFNumberGetTypeID()) {
if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberDoubleType, result) &&
!CFNumberGetValue((CFNumberRef) cf, kCFNumberFloatType, result)) {
return "Number type is not Double or Float";
}
return nullptr;
}
return "TypeID is neither 'CFNumber'";
}
const char* ffCfDateGetEpoch(CFTypeRef cf, uint64_t* result) {
if (CFGetTypeID(cf) != CFDateGetTypeID()) {
return "TypeID is not 'CFDate'";
}
CFAbsoluteTime absTime = CFDateGetAbsoluteTime((CFDateRef) cf);
// Convert from seconds to milliseconds and add the difference between 1970 and 2001 in milliseconds
*result = (uint64_t) ((absTime + 978307200 /*kCFAbsoluteTimeIntervalSince1970*/) * 1000);
return nullptr;
}
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) {
ffStrbufClear(result);
if (!cf) {
return NULL;
return nullptr;
}
if (CFGetTypeID(cf) == CFStringGetTypeID()) {
@@ -49,7 +72,7 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) {
} else {
uint32_t length = (uint32_t) CFStringGetLength(cfStr);
if (length == 0) {
return NULL;
return nullptr;
}
ffStrbufEnsureFixedLengthFree(result, (uint32_t) CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8));
if (!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) {
@@ -63,7 +86,7 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) {
CFDataRef cfData = (CFDataRef) cf;
uint32_t length = (uint32_t) CFDataGetLength(cfData);
if (length == 0) {
return NULL;
return nullptr;
}
ffStrbufEnsureFixedLengthFree(result, length + 1);
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*) result->chars);
@@ -73,20 +96,20 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) {
return "TypeID is neither 'CFString' nor 'CFData'";
}
return NULL;
return nullptr;
}
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result) {
ffStrbufClear(result);
if (!cf) {
return NULL;
return nullptr;
}
if (CFGetTypeID(cf) == CFDataGetTypeID()) {
CFDataRef cfData = (CFDataRef) cf;
uint32_t length = (uint32_t) CFDataGetLength(cfData);
if (length == 0) {
return NULL;
return nullptr;
}
ffStrbufEnsureFixedLengthFree(result, length + 1);
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*) result->chars);
@@ -96,12 +119,12 @@ const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result) {
return "TypeID is not 'CFData'";
}
return NULL;
return nullptr;
}
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) {
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
if (cf == NULL) {
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
@@ -110,7 +133,7 @@ const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* r
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) {
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
if (cf == NULL) {
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
@@ -119,7 +142,7 @@ const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstr
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) {
CFBooleanRef cf = (CFBooleanRef) CFDictionaryGetValue(dict, key);
if (cf == NULL) {
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
@@ -128,12 +151,12 @@ const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result)
}
*result = CFBooleanGetValue(cf);
return NULL;
return nullptr;
}
const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result) {
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
if (cf == NULL) {
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
@@ -142,16 +165,25 @@ const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result) {
const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result) {
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
if (cf == NULL) {
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
return ffCfNumGetInt64(cf, result);
}
const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* result) {
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
return ffCfNumGetDouble(cf, result);
}
const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length) {
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
if (cf == NULL) {
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
@@ -170,15 +202,24 @@ const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offs
}
CFDataGetBytes((CFDataRef) cf, CFRangeMake(offset, size), result);
return NULL;
return nullptr;
}
const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result) {
CFDictionaryRef cf = (CFDictionaryRef) CFDictionaryGetValue(dict, key);
if (cf == NULL || CFGetTypeID(cf) != CFDictionaryGetTypeID()) {
if (cf == nullptr || CFGetTypeID(cf) != CFDictionaryGetTypeID()) {
return "TypeID is not 'CFDictionary'";
}
*result = cf;
return NULL;
return nullptr;
}
const char* ffCfDictGetDateAsEpoch(CFDictionaryRef dict, CFStringRef key, uint64_t* result) {
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
return ffCfDateGetEpoch(cf, result);
}
+7 -3
View File
@@ -4,18 +4,22 @@
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
// Return error info if failed, NULL otherwise
// Return error info if failed, nullptr otherwise
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result);
const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result);
const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result);
const char* ffCfNumGetDouble(CFTypeRef cf, double* result);
const char* ffCfDateGetEpoch(CFTypeRef cf, uint64_t* result);
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result);
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result);
const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result);
const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result);
const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* result);
const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length);
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result);
const char* ffCfDictGetDateAsEpoch(CFDictionaryRef dict, CFStringRef key, uint64_t* result);
static inline CFNumberRef ffCfCreateInt(int value) {
return CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value);
@@ -28,7 +32,7 @@ static inline void cfReleaseWrapper(void* type) {
}
}
#define FF_CFTYPE_AUTO_RELEASE FF_A_CLEANUP(cfReleaseWrapper)
#define FF_CFTYPE_AUTO_RELEASE [[gnu::cleanup(cfReleaseWrapper)]]
static inline void wrapIoObjectRelease(io_object_t* service) {
assert(service);
@@ -36,4 +40,4 @@ static inline void wrapIoObjectRelease(io_object_t* service) {
IOObjectRelease(*service);
}
}
#define FF_IOOBJECT_AUTO_RELEASE FF_A_CLEANUP(wrapIoObjectRelease)
#define FF_IOOBJECT_AUTO_RELEASE [[gnu::cleanup(wrapIoObjectRelease)]]
-2
View File
@@ -1,8 +1,6 @@
#include "osascript.h"
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <CoreData/CoreData.h>
bool ffOsascript(const char* input, FFstrbuf* result)
{
+46 -12
View File
@@ -1,9 +1,8 @@
#include "smc_temps.h"
#include "common/apple/cf_helpers.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include <stdint.h>
#include <math.h>
#include <IOKit/IOKitLib.h>
static const char kSmcCmdReadBytes = 5;
@@ -87,7 +86,7 @@ static const char* smcCall(io_connect_t conn, uint32_t selector, SmcKeyData_t* i
if (IOConnectCallStructMethod(conn, selector, inputStructure, size, outputStructure, &size) != kIOReturnSuccess) {
return "IOConnectCallStructMethod(conn) failed";
}
return NULL;
return nullptr;
}
// Provides key info, using a cache to dramatically improve the energy impact of smcFanControl
@@ -104,7 +103,7 @@ static const char* smcGetKeyInfo(io_connect_t conn, const uint32_t key, SmcKeyDa
}
*key_info = outputStructure.keyInfo;
return NULL;
return nullptr;
}
static const char* smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcVal_t* val) {
@@ -131,7 +130,7 @@ static const char* smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcV
memcpy(val->bytes, outputStructure.bytes, sizeof(outputStructure.bytes));
return NULL;
return nullptr;
}
static const char* smcOpen(io_connect_t* conn) {
@@ -144,13 +143,13 @@ static const char* smcOpen(io_connect_t* conn) {
return "IOServiceOpen() failed";
}
return NULL;
return nullptr;
}
static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, double* value) {
SmcVal_t val = { 0 };
const char* error = smcReadSmcVal(conn, key, &val);
if (error != NULL) {
if (error != nullptr) {
return error;
}
if (val.dataSize == 0) {
@@ -271,7 +270,7 @@ static const char* smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl
default:
return "Unsupported SMC data type";
}
return NULL;
return nullptr;
}
static bool detectTemp(io_connect_t conn, const char* sensor, double* sum) {
@@ -292,7 +291,7 @@ static io_connect_t conn;
const char* ffDetectSmcSpecificTemp(const char* sensor, double* result) {
if (!conn) {
if (smcOpen(&conn) != NULL) {
if (smcOpen(&conn) != nullptr) {
conn = (io_connect_t) -1;
}
}
@@ -304,12 +303,12 @@ const char* ffDetectSmcSpecificTemp(const char* sensor, double* result) {
return "Could not read SMC temperature";
}
return NULL;
return nullptr;
}
const char* ffDetectSmcTemps(enum FFTempType type, double* result) {
if (!conn) {
if (smcOpen(&conn) != NULL) {
if (smcOpen(&conn) != nullptr) {
conn = (io_connect_t) -1;
}
}
@@ -393,6 +392,27 @@ const char* ffDetectSmcTemps(enum FFTempType type, double* result) {
count += detectTemp(conn, "Tp0e", result); // CPU performance core 8
break;
case FF_TEMP_CPU_M5X:
count += detectTemp(conn, "Tp00", result); // CPU super core 1
count += detectTemp(conn, "Tp04", result); // CPU super core 2
count += detectTemp(conn, "Tp08", result); // CPU super core 3
count += detectTemp(conn, "Tp0C", result); // CPU super core 4
count += detectTemp(conn, "Tp0G", result); // CPU super core 5
count += detectTemp(conn, "Tp0K", result); // CPU super core 6
count += detectTemp(conn, "Tp0O", result); // CPU performance core 1
count += detectTemp(conn, "Tp0R", result); // CPU performance core 2
count += detectTemp(conn, "Tp0U", result); // CPU performance core 3
count += detectTemp(conn, "Tp0X", result); // CPU performance core 4
count += detectTemp(conn, "Tp0a", result); // CPU performance core 5
count += detectTemp(conn, "Tp0d", result); // CPU performance core 6
count += detectTemp(conn, "Tp0g", result); // CPU performance core 7
count += detectTemp(conn, "Tp0j", result); // CPU performance core 8
count += detectTemp(conn, "Tp0m", result); // CPU performance core 9
count += detectTemp(conn, "Tp0p", result); // CPU performance core 10
count += detectTemp(conn, "Tp0u", result); // CPU performance core 11
count += detectTemp(conn, "Tp0y", result); // CPU performance core 12
break;
case FF_TEMP_GPU_INTEL:
count += detectTemp(conn, "TCGC", result); // GPU Intel Graphics
goto gpu_unknown;
@@ -443,6 +463,17 @@ const char* ffDetectSmcTemps(enum FFTempType type, double* result) {
count += detectTemp(conn, "Tg0k", result); // GPU 8
break;
case FF_TEMP_GPU_M5X:
count += detectTemp(conn, "Tg0U", result); // GPU 1
count += detectTemp(conn, "Tg0X", result); // GPU 2
count += detectTemp(conn, "Tg0d", result); // GPU 3
count += detectTemp(conn, "Tg0g", result); // GPU 4
count += detectTemp(conn, "Tg0j", result); // GPU 5
count += detectTemp(conn, "Tg1Y", result); // GPU 6
count += detectTemp(conn, "Tg1c", result); // GPU 7
count += detectTemp(conn, "Tg1g", result); // GPU 8
break;
case FF_TEMP_BATTERY:
count += detectTemp(conn, "TB1T", result); // Battery
count += detectTemp(conn, "TB2T", result); // Battery
@@ -453,6 +484,9 @@ const char* ffDetectSmcTemps(enum FFTempType type, double* result) {
count += detectTemp(conn, "Tm06", result); // Memory 2
count += detectTemp(conn, "Tm08", result); // Memory 3
count += detectTemp(conn, "Tm09", result); // Memory 4
count += detectTemp(conn, "Tm0p", result); // Memory Proximity 1 (M4)
count += detectTemp(conn, "Tm1p", result); // Memory Proximity 2 (M4)
count += detectTemp(conn, "Tm2p", result); // Memory Proximity 3 (M4)
break;
}
@@ -462,5 +496,5 @@ const char* ffDetectSmcTemps(enum FFTempType type, double* result) {
*result /= count;
return NULL;
return nullptr;
}
+3 -1
View File
@@ -8,12 +8,13 @@ typedef struct FFTempValue {
double value;
} FFTempValue;
enum FFTempType {
enum FFTempType: uint8_t {
FF_TEMP_CPU_X64,
FF_TEMP_CPU_M1X,
FF_TEMP_CPU_M2X,
FF_TEMP_CPU_M3X,
FF_TEMP_CPU_M4X,
FF_TEMP_CPU_M5X,
FF_TEMP_GPU_INTEL,
FF_TEMP_GPU_AMD,
@@ -22,6 +23,7 @@ enum FFTempType {
FF_TEMP_GPU_M2X,
FF_TEMP_GPU_M3X,
FF_TEMP_GPU_M4X,
FF_TEMP_GPU_M5X,
FF_TEMP_BATTERY,
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "fastfetch.h"
bool ffGetAppNameAndVersion(const char* exePath, FFstrbuf* retName, FFstrbuf* retVersion);
+43
View File
@@ -0,0 +1,43 @@
#include "common/apple/version.h"
#include "common/strutil.h"
#import <Foundation/Foundation.h>
#define APP_CONTENTS_MACOS ".app/Contents/MacOS"
bool ffGetAppNameAndVersion(const char* exePath, FFstrbuf* retName, FFstrbuf* retVersion) {
char* lastSlash = strrchr(exePath, '/');
if (!lastSlash) {
return false;
}
if ((size_t) (lastSlash - exePath) > strlen("X" APP_CONTENTS_MACOS) && memcmp(lastSlash - strlen(APP_CONTENTS_MACOS), APP_CONTENTS_MACOS, strlen(APP_CONTENTS_MACOS)) != 0) {
return false;
}
lastSlash -= strlen("MacOS");
char infoPlistPath[PATH_MAX];
memcpy(infoPlistPath, exePath, (size_t) (lastSlash - exePath));
memcpy(infoPlistPath + (lastSlash - exePath), "Info.plist", sizeof("Info.plist")); // X.app/Contents/Info.plist
NSError* error;
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@(infoPlistPath)]
error:&error];
if (!dict) {
return false;
}
if (retName) {
NSString* bundleName = dict[@"CFBundleDisplayName"] ?: dict[@"CFBundleName"];
if (bundleName) {
ffStrbufSetS(retName, bundleName.UTF8String);
}
}
if (retVersion) {
NSString* bundleVersion = dict[@"CFBundleShortVersionString"];
if (bundleVersion) {
ffStrbufSetS(retVersion, bundleVersion.UTF8String);
}
}
return true;
}
+1 -1
View File
@@ -10,7 +10,7 @@ typedef struct FFArgBuffer {
uint32_t length;
} FFArgBuffer;
typedef enum FF_A_PACKED FFArgType {
typedef enum FFArgType: uint8_t {
FF_ARG_TYPE_NULL = 0,
FF_ARG_TYPE_UINT,
FF_ARG_TYPE_UINT64,
@@ -6,9 +6,9 @@
#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))); })
#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))); })
#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))); })
#endif
#endif
#ifndef ARRAY_SIZE
-18
View File
@@ -1,18 +0,0 @@
#pragma once
#ifndef __has_attribute
#error Unsupported compiler
#define __attribute__(x)
#endif
#define FF_A_FALLTHROUGH __attribute__((__fallthrough__))
#define FF_A_DEPRECATED __attribute__((__deprecated__))
#define FF_A_CLEANUP(func) __attribute__((__cleanup__(func)))
#define FF_A_NODISCARD __attribute__((__warn_unused_result__))
#define FF_A_PRINTF(formatStrIndex, argsStartIndex) __attribute__((__format__(printf, formatStrIndex, argsStartIndex)))
#define FF_A_SCANF(formatStrIndex, argsStartIndex) __attribute__((__format__(scanf, formatStrIndex, argsStartIndex)))
#define FF_A_NONNULL(argIndex, ...) __attribute__((__nonnull__(argIndex, ##__VA_ARGS__)))
#define FF_A_RETURNS_NONNULL __attribute__((__returns_nonnull__))
#define FF_A_UNUSED __attribute__((__unused__))
#define FF_A_PACKED __attribute__((__packed__))
#define FF_A_WEAK_IMPORT __attribute__((__weak_import__))
+1 -1
View File
@@ -11,7 +11,7 @@
* @param userdata User-provided data passed to the callback function
* @param minLength Minimum length of strings to extract
*
* @return NULL on success, error message on failure.
* @return nullptr on success, error message on failure.
* @note This function won't return an error if no strings are found.
* Always check if strings are correctly extracted after this function all.
*/
+10
View File
@@ -10,6 +10,16 @@
#define FF_COLOR_MODE_HIDDEN "8;"
#define FF_COLOR_MODE_STRIKETHROUGH "9;"
#define FF_COLOR_MODE_RESET_ "0"
#define FF_COLOR_MODE_BOLD_ "1"
#define FF_COLOR_MODE_DIM_ "2"
#define FF_COLOR_MODE_ITALIC_ "3"
#define FF_COLOR_MODE_UNDERLINE_ "4"
#define FF_COLOR_MODE_BLINK_ "5"
#define FF_COLOR_MODE_INVERSE_ "7"
#define FF_COLOR_MODE_HIDDEN_ "8"
#define FF_COLOR_MODE_STRIKETHROUGH_ "9"
#define FF_COLOR_FG_BLACK "30"
#define FF_COLOR_FG_RED "31"
#define FF_COLOR_FG_GREEN "32"
+6 -6
View File
@@ -26,21 +26,21 @@ typedef struct FFDBusData {
DBusConnection* connection;
} FFDBusData;
const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); // Returns an error message or NULL on success
const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); // Returns an error message or nullptr on success
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result);
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result);
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint64_t* result);
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2);
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property);
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int64_t* result);
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint64_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);
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, nullptr);
}
#define FF_DBUS_AUTO_DESTROY_DATA FF_A_CLEANUP(ffDBusDestroyData)
#define FF_DBUS_AUTO_DESTROY_DATA [[gnu::cleanup(ffDBusDestroyData)]]
#endif // FF_HAVE_DBUS
+3 -2
View File
@@ -6,11 +6,11 @@
static inline const char* ffFindFileName(const char* file) {
const char* lastSlash = __builtin_strrchr(file, '/');
#ifdef _WIN32
if (lastSlash == NULL) {
if (lastSlash == nullptr) {
lastSlash = __builtin_strrchr(file, '\\');
}
#endif
if (lastSlash != NULL) {
if (lastSlash != nullptr) {
return lastSlash + 1;
}
return file;
@@ -33,5 +33,6 @@ static inline const char* ffFindFileName(const char* file) {
#if _WIN32
const char* ffDebugWin32Error(DWORD errorCode);
const char* ffDebugNtStatus(NTSTATUS status);
const char* ffDebugConfigRet(unsigned long /*CONFIGRET*/ ret);
const char* ffDebugHResult(HRESULT hr);
#endif
+2 -1
View File
@@ -8,6 +8,7 @@ bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name);
void ffEdidGetPreferredResolutionAndRefreshRate(const uint8_t edid[128], uint32_t* width, uint32_t* height, double* refreshRate);
void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height);
void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week);
void ffEdidGetManufactureDate(const uint8_t edid[128], uint16_t* year, uint16_t* week);
bool ffEdidGetSerial(const uint8_t edid[128], FFstrbuf* result);
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length);
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length);
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <stdint.h>
#if __BIG_ENDIAN__
#define FF_READ_LE(x) _Generic((x), \
uint16_t: __builtin_bswap16(x), \
uint32_t: __builtin_bswap32(x), \
uint64_t: __builtin_bswap64(x))
#define FF_READ_BE(x) (x)
#else
#define FF_READ_LE(x) (x)
#define FF_READ_BE(x) _Generic((x), \
uint16_t: __builtin_bswap16(x), \
uint32_t: __builtin_bswap32(x), \
uint64_t: __builtin_bswap64(x))
#endif
+2 -1
View File
@@ -2,7 +2,7 @@
#include "common/FFstrbuf.h"
typedef enum FF_A_PACKED FFDataResultDocType {
typedef enum FFDataResultDocType: uint8_t {
FF_RESULT_DOC_TYPE_DEFAULT = 0,
FF_RESULT_DOC_TYPE_JSON,
FF_RESULT_DOC_TYPE_CONFIG,
@@ -19,4 +19,5 @@ typedef struct FFdata {
FFstrbuf genConfigPath; // Path to generate configuration file
FFDataResultDocType docType; // Type of result document
bool configLoaded;
bool genConfigInteractive; // `--gen-config` entered the interactive CUI
} FFdata;
+1 -1
View File
@@ -21,5 +21,5 @@ void ffFontInitWithSpace(FFfont* font, const char* rawName);
void ffFontDestroy(FFfont* font);
static inline void ffFontInitCopy(FFfont* font, const char* name) {
ffFontInitValues(font, name, NULL);
ffFontInitValues(font, name, nullptr);
}
+1 -1
View File
@@ -9,6 +9,6 @@ typedef struct FFformatarg {
} FFformatarg;
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg);
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments);
bool ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments);
#define FF_PARSE_FORMAT_STRING_CHECKED(buffer, formatstr, arguments) \
ffParseFormatString((buffer), (formatstr), sizeof(arguments) / sizeof(*arguments), (arguments));
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "common/ffdata.h"
// Runs the interactive config generation CUI.
//
// On success (the user saved the config), it sets `data->structure` to the user chosen
// module structure and `instance.config.logo.type` to the user chosen logo type, creates
// the result document and returns true. The caller is expected to call `writeConfigFile`.
// Returns false if the user quits without saving.
bool ffGenConfigInteractive(FFdata* data);
+3 -1
View File
@@ -1,5 +1,5 @@
#include "FFPlatform_private.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "common/io.h"
#include "detection/version/version.h"
@@ -18,6 +18,7 @@ void ffPlatformInit(FFPlatform* platform) {
#ifdef _WIN32
ffStrbufInit(&platform->sid);
platform->initCP = 0;
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
@@ -26,6 +27,7 @@ void ffPlatformInit(FFPlatform* platform) {
ffStrbufInit(&info->release);
ffStrbufInit(&info->version);
ffStrbufInit(&info->architecture);
info->pageSize = 0;
ffPlatformInitImpl(platform);
+51 -37
View File
@@ -1,9 +1,10 @@
#include "FFPlatform_private.h"
#include "common/FFstrbuf.h"
#include "common/arrayUtils.h"
#include "common/stringUtils.h"
#include "common/arrutil.h"
#include "common/strutil.h"
#include "common/io.h"
#include "fastfetch_config.h"
#include "common/path.h"
#include "common/mallocHelper.h"
#include <unistd.h>
#include <pwd.h>
@@ -18,7 +19,7 @@
#include <sys/sysctl.h>
#elif defined(__OpenBSD__)
#include <sys/sysctl.h>
#include <kvm.h>
#include <sys/stat.h>
#include "common/path.h"
#elif defined(__HAIKU__)
#include <image.h>
@@ -29,7 +30,7 @@ static void getExePath(FFPlatform* platform) {
char exePath[PATH_MAX];
#if defined(__linux__) || defined(__GNU__)
ssize_t exePathLen = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
if (exePathLen >= 0) {
if (exePathLen > 0) {
exePath[exePathLen] = '\0';
}
#elif defined(__APPLE__)
@@ -56,7 +57,7 @@ static void getExePath(FFPlatform* platform) {
4,
exePath,
&exePathLen,
NULL,
nullptr,
0) < 0)
exePathLen = 0;
else {
@@ -67,16 +68,17 @@ static void getExePath(FFPlatform* platform) {
// 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 argvBuf[ARG_MAX];
size_t argvSize = sizeof(argvBuf);
int argvMib[] = { CTL_KERN, KERN_PROC_ARGS, (pid_t) platform->pid, KERN_PROC_ARGV };
if (sysctl(argvMib, ARRAY_SIZE(argvMib), argvBuf, &argvSize, nullptr, 0) == 0) {
// The buffer is filled with an array of char pointers followed by the strings themselves
char** argv = (char**) argvBuf;
if (argv[0] && (char*) argv[0] >= argvBuf && (char*) argv[0] < argvBuf + argvSize) {
char* arg0 = argv[0];
if (arg0[0]) {
if (strchr(arg0, '/') != NULL) // likely a path (absolute or relative)
if (strchr(arg0, '/') != nullptr) // likely a path (absolute or relative)
{
exePathLen = strlen(arg0);
if (exePathLen < ARRAY_SIZE(exePath)) {
@@ -87,7 +89,7 @@ static void getExePath(FFPlatform* platform) {
}
} else {
FF_STRBUF_AUTO_DESTROY tmpPath = ffStrbufCreate();
if (ffFindExecutableInPath(arg0, &tmpPath) == NULL && tmpPath.length < ARRAY_SIZE(exePath)) {
if (ffFindExecutableInPath(arg0, &tmpPath) == nullptr && tmpPath.length < ARRAY_SIZE(exePath)) {
memcpy(exePath, tmpPath.chars, tmpPath.length + 1);
exePathLen = tmpPath.length;
}
@@ -96,25 +98,38 @@ static void getExePath(FFPlatform* platform) {
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;
// Replicate kvm_getfiles()'s live path: {CTL_KERN, KERN_FILE, KERN_FILE_BYPID, pid, esize, count}
int fileMib[6] = { CTL_KERN, KERN_FILE, KERN_FILE_BYPID, (pid_t) platform->pid, (int) sizeof(struct kinfo_file), 0 };
size_t fileSize = 0;
if (sysctl(fileMib, ARRAY_SIZE(fileMib), nullptr, &fileSize, nullptr, 0) == 0) {
fileSize += fileSize / 8; // add ~10%
FF_AUTO_FREE struct kinfo_file* kf = (struct kinfo_file*) malloc(fileSize);
if (kf) {
int rv;
do {
fileMib[5] = (int) (fileSize / sizeof(struct kinfo_file));
rv = sysctl(fileMib, ARRAY_SIZE(fileMib), kf, &fileSize, nullptr, 0);
} while (rv == -1 && errno == ENOMEM);
if (rv == 0) {
int cntp = (int) (fileSize / sizeof(struct kinfo_file));
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;
}
break;
}
// If we can't get the list of open files, we can't verify that the file is actually the executable
// Assume it is
}
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;
@@ -123,11 +138,10 @@ static void getExePath(FFPlatform* platform) {
}
}
}
kvm_close(kd);
}
#elif defined(__sun)
ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1);
if (exePathLen >= 0) {
if (exePathLen > 0) {
exePath[exePathLen] = '\0';
}
#elif defined(__HAIKU__)
@@ -237,8 +251,8 @@ static void getDataDirs(FFPlatform* platform) {
ffPlatformPathAddHome(&platform->dataDirs, platform, "");
platformPathAddEnv(&platform->dataDirs, "XDG_DATA_DIRS");
#ifdef _PATH_LOCALBASE
ffPlatformPathAddAbsolute(&platform->dataDirs, _PATH_LOCALBASE "/share/");
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
ffPlatformPathAddAbsolute(&platform->dataDirs, FF_PATH_PKG_BASE "/share/");
#endif
ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR "/local/share/");
ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR "/share/");
@@ -281,7 +295,7 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts) {
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
size_t length = sizeof(info->pageSize);
sysctl((int[]) { CTL_HW, HW_PAGESIZE }, 2, &info->pageSize, &length, NULL, 0);
sysctl((int[]) { CTL_HW, HW_PAGESIZE }, 2, &info->pageSize, &length, nullptr, 0);
#else
info->pageSize = (uint32_t) sysconf(_SC_PAGESIZE);
#endif
@@ -289,7 +303,7 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts) {
static void getCwd(FFPlatform* platform) {
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
if (getcwd(cwd, sizeof(cwd)) != nullptr) {
ffStrbufSetS(&platform->cwd, cwd);
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
}
+52 -68
View File
@@ -1,7 +1,7 @@
#include "FFPlatform_private.h"
#include "common/io.h"
#include "common/library.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "common/windows/unicode.h"
#include "common/windows/registry.h"
#include "common/windows/nt.h"
@@ -21,10 +21,10 @@ static void getExePath(FFPlatform* platform) {
ffGetPeb()->ProcessParameters->ImagePathName.Buffer,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
nullptr);
if (hPath != INVALID_HANDLE_VALUE) {
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_NORMALIZED);
if (len > 0 && len < MAX_PATH) {
@@ -44,8 +44,8 @@ static void getExePath(FFPlatform* platform) {
}
static void getHomeDir(FFPlatform* platform) {
PWSTR pPath = NULL;
if (SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DEFAULT, NULL, &pPath))) {
PWSTR pPath = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DEFAULT, nullptr, &pPath))) {
ffStrbufSetWS(&platform->homeDir, pPath);
ffStrbufReplaceAllC(&platform->homeDir, '\\', '/');
ffStrbufEnsureEndsWithC(&platform->homeDir, '/');
@@ -58,8 +58,8 @@ static void getHomeDir(FFPlatform* platform) {
}
static void getCacheDir(FFPlatform* platform) {
PWSTR pPath = NULL;
if (SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, NULL, &pPath))) {
PWSTR pPath = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, nullptr, &pPath))) {
ffStrbufSetWS(&platform->cacheDir, pPath);
ffStrbufReplaceAllC(&platform->cacheDir, '\\', '/');
ffStrbufEnsureEndsWithC(&platform->cacheDir, '/');
@@ -71,8 +71,8 @@ static void getCacheDir(FFPlatform* platform) {
}
static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId) {
PWSTR pPath = NULL;
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, NULL, &pPath))) {
PWSTR pPath = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, nullptr, &pPath))) {
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateWS(pPath);
CoTaskMemFree(pPath);
ffStrbufReplaceAllC(&buffer, '\\', '/');
@@ -107,7 +107,7 @@ static void getConfigDirs(FFPlatform* platform) {
if (getenv("MSYSTEM")) {
// We are in MSYS2 / Git Bash
platformPathAddEnvSuffix(&platform->configDirs, "HOME", ".config/");
platformPathAddEnvSuffix(&platform->configDirs, "HOME", NULL);
platformPathAddEnvSuffix(&platform->configDirs, "HOME", nullptr);
platformPathAddEnvSuffix(&platform->configDirs, "MINGW_PREFIX", "etc");
}
@@ -122,7 +122,7 @@ static void getDataDirs(FFPlatform* platform) {
if (getenv("MSYSTEM") && getenv("HOME")) {
// We are in MSYS2 / Git Bash
platformPathAddEnvSuffix(&platform->dataDirs, "HOME", ".local/share/");
platformPathAddEnvSuffix(&platform->dataDirs, "HOME", NULL);
platformPathAddEnvSuffix(&platform->dataDirs, "HOME", nullptr);
platformPathAddEnvSuffix(&platform->dataDirs, "MINGW_PREFIX", "share");
}
ffPlatformPathAddHome(&platform->dataDirs, platform, ".local/share/");
@@ -142,10 +142,10 @@ static void getUserName(FFPlatform* platform) {
NTSYSAPI NTSTATUS NTAPI LsaGetUserName(
_Outptr_ PLSA_UNICODE_STRING * UserName,
_Outptr_opt_ PLSA_UNICODE_STRING * DomainName);
PLSA_UNICODE_STRING userName = NULL;
if (NT_SUCCESS(LsaGetUserName(&userName, NULL))) {
PLSA_UNICODE_STRING userName = nullptr;
if (NT_SUCCESS(LsaGetUserName(&userName, nullptr))) {
ffStrbufSetNWS(&platform->userName, userName->Length / sizeof(wchar_t), userName->Buffer);
RtlFreeUnicodeString(userName);
RtlFreeUnicodeString(userName); // Required. userName.Buffer is allocated separately
LsaFreeMemory(userName);
} else {
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
@@ -187,18 +187,18 @@ static const char* detectWine(void) {
const char* __cdecl wine_get_version(void);
void* hntdll = ffLibraryGetModule(L"ntdll.dll");
if (!hntdll) {
return NULL;
return nullptr;
}
FF_LIBRARY_LOAD_SYMBOL_LAZY(hntdll, wine_get_version);
if (!ffwine_get_version) {
return NULL;
return nullptr;
}
return ffwine_get_version();
}
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info) {
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL)) {
FF_AUTO_CLOSE_FD HANDLE hKey = nullptr;
if (!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, nullptr)) {
return;
}
@@ -207,7 +207,7 @@ static void getSystemReleaseAndVersion(FFPlatformSysinfo* info) {
FF_ARG(ubr, L"UBR"),
FF_ARG(info->version, L"BuildLabEx"),
},
NULL);
nullptr);
PPEB_FULL peb = ffGetPeb();
@@ -228,7 +228,7 @@ static void getSystemReleaseAndVersion(FFPlatformSysinfo* info) {
static void getSystemPageSize(FFPlatformSysinfo* info) {
SYSTEM_BASIC_INFORMATION sbi;
if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL))) {
if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), nullptr))) {
info->pageSize = sbi.PhysicalPageSize;
} else {
info->pageSize = 4096;
@@ -236,54 +236,38 @@ static void getSystemPageSize(FFPlatformSysinfo* info) {
}
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;
case PROCESSOR_ARCHITECTURE_IA64:
ffStrbufSetStatic(&info->architecture, "ia64");
break;
case PROCESSOR_ARCHITECTURE_INTEL:
switch (spi.ProcessorLevel) {
case 4:
ffStrbufSetStatic(&info->architecture, "i486");
break;
case 5:
ffStrbufSetStatic(&info->architecture, "i586");
break;
case 6:
ffStrbufSetStatic(&info->architecture, "i686");
break;
default:
ffStrbufSetStatic(&info->architecture, "i386");
break;
}
break;
case PROCESSOR_ARCHITECTURE_ARM64:
ffStrbufSetStatic(&info->architecture, "aarch64");
break;
case PROCESSOR_ARCHITECTURE_ARM:
ffStrbufSetStatic(&info->architecture, "arm");
break;
case PROCESSOR_ARCHITECTURE_PPC:
ffStrbufSetStatic(&info->architecture, "ppc");
break;
case PROCESSOR_ARCHITECTURE_MIPS:
ffStrbufSetStatic(&info->architecture, "mips");
break;
case PROCESSOR_ARCHITECTURE_ALPHA:
ffStrbufSetStatic(&info->architecture, "alpha");
break;
case PROCESSOR_ARCHITECTURE_ALPHA64:
ffStrbufSetStatic(&info->architecture, "alpha64");
break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
default:
ffStrbufSetStatic(&info->architecture, "unknown");
break;
}
switch (SharedUserData->NativeProcessorArchitecture) {
case PROCESSOR_ARCHITECTURE_AMD64:
ffStrbufSetStatic(&info->architecture, "x86_64");
break;
case PROCESSOR_ARCHITECTURE_IA64:
ffStrbufSetStatic(&info->architecture, "ia64");
break;
case PROCESSOR_ARCHITECTURE_INTEL:
ffStrbufSetStatic(&info->architecture, "i686");
break;
case PROCESSOR_ARCHITECTURE_ARM64:
ffStrbufSetStatic(&info->architecture, "aarch64");
break;
case PROCESSOR_ARCHITECTURE_ARM:
ffStrbufSetStatic(&info->architecture, "arm");
break;
case PROCESSOR_ARCHITECTURE_PPC:
ffStrbufSetStatic(&info->architecture, "ppc");
break;
case PROCESSOR_ARCHITECTURE_MIPS:
ffStrbufSetStatic(&info->architecture, "mips");
break;
case PROCESSOR_ARCHITECTURE_ALPHA:
ffStrbufSetStatic(&info->architecture, "alpha");
break;
case PROCESSOR_ARCHITECTURE_ALPHA64:
ffStrbufSetStatic(&info->architecture, "alpha64");
break;
case PROCESSOR_ARCHITECTURE_UNKNOWN:
default:
ffStrbufSetStatic(&info->architecture, "unknown");
break;
}
}
+2 -11
View File
@@ -3,16 +3,7 @@
#include <stdlib.h>
#include <string.h>
void* ffListAdd(FFlist* list, uint32_t elementSize) {
if (list->length == list->capacity) {
ffListReserve(list, elementSize, list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2);
}
++list->length;
return ffListGet(list, elementSize, list->length - 1);
}
bool ffListShift(FFlist* list, uint32_t elementSize, void* result) {
bool ffListShift(FFlist* list, uint32_t elementSize, void* __restrict result) {
if (list->length == 0) {
return false;
}
@@ -23,7 +14,7 @@ bool ffListShift(FFlist* list, uint32_t elementSize, void* result) {
return true;
}
bool ffListPop(FFlist* list, uint32_t elementSize, void* result) {
bool ffListPop(FFlist* list, uint32_t elementSize, void* __restrict result) {
if (list->length == 0) {
return false;
}
+79 -134
View File
@@ -1,6 +1,7 @@
#include "common/FFstrbuf.h"
#include "common/mallocHelper.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "common/debug.h"
#include <ctype.h>
#include <inttypes.h>
@@ -20,9 +21,9 @@ void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate) {
}
void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments) {
assert(format != NULL);
assert(format != nullptr);
char* buffer = NULL;
char* buffer = nullptr;
int len = vasprintf(&buffer, format, arguments);
assert(len >= 0);
@@ -32,7 +33,7 @@ void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments) {
// 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);
assert(heapStr != nullptr);
strbuf->length = length;
size_t allocSize = ffMallocUsableSize(heapStr);
@@ -45,18 +46,45 @@ void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr) {
strbuf->chars = heapStr;
}
void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) {
if (ffStrbufGetFree(strbuf) >= free && !(strbuf->allocated == 0 && strbuf->length > 0)) {
return;
void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...) {
va_list arguments;
va_start(arguments, format);
ffStrbufInitVF(strbuf, format, arguments);
va_end(arguments);
}
FFstrbuf ffStrbufCreateF(const char* format, ...) {
FFstrbuf strbuf;
va_list arguments;
va_start(arguments, format);
ffStrbufInitVF(&strbuf, format, arguments);
va_end(arguments);
return strbuf;
}
void ffStrbufEnsureFreeNoCheck(FFstrbuf* strbuf, uint32_t free) {
uint32_t allocate;
if (__builtin_expect(__builtin_uadd_overflow(strbuf->length, free, &allocate), false)) {
FF_DEBUG("Error: Integer overflow when calculating allocation size. Aborting");
abort();
}
uint32_t allocate = strbuf->allocated;
if (allocate < FASTFETCH_STRBUF_DEFAULT_ALLOC) {
if (allocate < FASTFETCH_STRBUF_DEFAULT_ALLOC) { // `<` for null terminator
allocate = FASTFETCH_STRBUF_DEFAULT_ALLOC;
}
} else {
if (__builtin_expect(allocate > (UINT32_MAX >> 1), false)) {
// User tried to allocate more than 2GB of memory, which exceeds the maximum size supported by FFstrbuf.
// This is likely an error or an attempt to exploit the program. Abort to prevent potential issues.
FF_DEBUG("Error: Attempted to allocate %" PRIu32 " bytes more than 2GB of memory in FFstrbuf. Aborting", allocate);
abort();
}
while ((strbuf->length + free + 1) > allocate) { // + 1 for the null byte
allocate *= 2;
// Round up to the next power of 2.
// If the value is already a power of 2, it will be rounded up to the next power of 2.
// allocate = __builtin_stdc_bit_ceil(allocate + 1); // Currently generates worse asm code
allocate = 1U << (32 - __builtin_clz(allocate));
}
if (strbuf->allocated == 0) {
@@ -76,16 +104,17 @@ void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) {
// 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)
// This function ensures a dynamic buffer is allocated even if free == 0
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free) {
uint32_t oldFree = ffStrbufGetFree(strbuf);
if (oldFree >= free && !(strbuf->allocated == 0 && strbuf->length > 0)) {
return;
}
uint32_t newCap = strbuf->allocated + (free - oldFree);
uint32_t newCap;
if (strbuf->allocated == 0) {
newCap += strbuf->length + 1;
assert(strbuf->length < UINT32_MAX - 1); // We don't use static strings with length >= UINT32_MAX - 1, so this should never happen
if (__builtin_expect(__builtin_uadd_overflow(strbuf->length + 1, free, &newCap), false)) {
FF_DEBUG("Error: Integer overflow when calculating new capacity. Aborting");
abort();
}
char* newbuf = malloc(sizeof(*strbuf->chars) * newCap);
if (strbuf->length == 0) {
*newbuf = '\0';
@@ -94,54 +123,23 @@ void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free) {
}
strbuf->chars = newbuf;
} else {
uint32_t oldFree = ffStrbufGetFree(strbuf);
if (oldFree >= free) {
return;
}
if (__builtin_expect(__builtin_uadd_overflow(strbuf->allocated, free - oldFree, &newCap), false)) {
FF_DEBUG("Error: Integer overflow when calculating new capacity. Aborting");
abort();
}
strbuf->chars = realloc(strbuf->chars, sizeof(*strbuf->chars) * newCap);
}
strbuf->allocated = newCap;
}
void ffStrbufClear(FFstrbuf* strbuf) {
assert(strbuf != NULL);
if (strbuf->allocated == 0) {
strbuf->chars = CHAR_NULL_PTR;
} else {
strbuf->chars[0] = '\0';
}
strbuf->length = 0;
}
void ffStrbufAppendC(FFstrbuf* strbuf, char c) {
ffStrbufEnsureFree(strbuf, 1);
strbuf->chars[strbuf->length++] = c;
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c) {
if (num == 0) {
return;
}
ffStrbufEnsureFree(strbuf, num);
memset(&strbuf->chars[strbuf->length], c, num);
strbuf->length += num;
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
if (value == NULL || length == 0) {
return;
}
ffStrbufEnsureFree(strbuf, length);
memcpy(&strbuf->chars[strbuf->length], value, length);
strbuf->length += length;
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int (*transformFunc)(int)) {
if (value == NULL) {
if (value == nullptr) {
return;
}
@@ -159,7 +157,7 @@ void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int (*transfo
}
void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments) {
assert(format != NULL);
assert(format != nullptr);
va_list copy;
va_copy(copy, arguments);
@@ -168,7 +166,7 @@ void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments) {
int written = vsnprintf(strbuf->chars + strbuf->length, strbuf->allocated > 0 ? free + 1 : 0, format, arguments);
if (written > 0 && (uint32_t) written > free) {
ffStrbufEnsureFree(strbuf, (uint32_t) written);
ffStrbufEnsureFreeNoCheck(strbuf, (uint32_t) written);
written = vsnprintf(strbuf->chars + strbuf->length, (uint32_t) written + 1, format, copy);
}
@@ -180,12 +178,12 @@ void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments) {
}
const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until) {
if (value == NULL) {
return NULL;
if (value == nullptr) {
return nullptr;
}
const char* end = strchr(value, until);
if (end == NULL) {
if (end == nullptr) {
ffStrbufAppendS(strbuf, value);
} else {
ffStrbufAppendNS(strbuf, (uint32_t) (end - value), value);
@@ -194,7 +192,7 @@ const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char unti
}
void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...) {
assert(format != NULL);
assert(format != nullptr);
va_list arguments;
va_start(arguments, format);
@@ -211,7 +209,7 @@ void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...) {
}
void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...) {
assert(format != NULL);
assert(format != nullptr);
va_list arguments;
va_start(arguments, format);
@@ -220,7 +218,7 @@ void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...) {
}
void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
if (value == NULL || length == 0) {
if (value == nullptr || length == 0) {
return;
}
@@ -238,14 +236,14 @@ void ffStrbufPrependC(FFstrbuf* strbuf, char c) {
}
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
assert(strbuf != NULL);
assert(strbuf != nullptr);
if (length == 0) {
ffStrbufClear(strbuf);
return;
}
assert(value != NULL);
assert(value != nullptr);
if (strbuf->allocated <= length) {
char* newBuf = malloc(sizeof(char) * (length + 1));
@@ -411,32 +409,6 @@ void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, const char* st
}
}
uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
assert(start <= strbuf->length);
const char* ptr = (const char*) memchr(strbuf->chars + start, c, strbuf->length - start);
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
}
uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) {
assert(start <= strbuf->length);
const char* ptr = strstr(strbuf->chars + start, str);
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
}
uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
assert(start <= strbuf->length);
// We need to loop one higher than the actual index, because uint32_t is guaranteed to be >= 0, so this statement would always be true
for (uint32_t i = start + 1; i > 0; i--) {
if (strbuf->chars[i - 1] == c) {
return i - 1;
}
}
return strbuf->length;
}
void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace) {
if (strbuf->length == 0) {
return;
@@ -461,9 +433,7 @@ bool ffStrbufSubstrBefore(FFstrbuf* strbuf, uint32_t index) {
if (strbuf->allocated == 0) {
// static string
if (index < strbuf->length) {
ffStrbufInitNS(strbuf, index, strbuf->chars);
}
ffStrbufInitNS(strbuf, index, strbuf->chars);
return true;
}
@@ -576,33 +546,6 @@ bool ffStrbufEnsureEndsWithC(FFstrbuf* strbuf, char c) {
return true;
}
void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file) {
fwrite(strbuf->chars, sizeof(*strbuf->chars), strbuf->length, file);
}
void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file) {
ffStrbufWriteTo(strbuf, file);
fputc('\n', file);
}
double ffStrbufToDouble(const FFstrbuf* strbuf, double defaultValue) {
char* str_end;
double result = strtod(strbuf->chars, &str_end);
return str_end == strbuf->chars ? defaultValue : result;
}
uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue) {
char* str_end;
unsigned long long result = strtoull(strbuf->chars, &str_end, 10);
return str_end == strbuf->chars ? defaultValue : (uint64_t) result;
}
int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue) {
char* str_end;
long long result = strtoll(strbuf->chars, &str_end, 10);
return str_end == strbuf->chars ? defaultValue : (int64_t) result;
}
void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value) {
ffStrbufEnsureFree(strbuf, 21); // Required by yyjson_write_number
char* start = strbuf->chars + strbuf->length;
@@ -611,7 +554,7 @@ void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value) {
unsafe_yyjson_set_sint(&val, value);
char* end = yyjson_write_number(&val, start);
assert(end != NULL);
assert(end != nullptr);
strbuf->length += (uint32_t) (end - start);
}
@@ -624,7 +567,7 @@ void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value) {
unsafe_yyjson_set_uint(&val, value);
char* end = yyjson_write_number(&val, start);
assert(end != NULL);
assert(end != nullptr);
strbuf->length += (uint32_t) (end - start);
}
@@ -790,9 +733,10 @@ bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const
}
for (const char* p = comp; p < comp + compLength;) {
const char* colon = memchr(p, separator, compLength);
if (colon == NULL) {
return strcmp(strbuf->chars, p) == 0;
const char* colon = memchr(p, separator, (size_t) (comp + compLength - p));
if (colon == nullptr) {
uint32_t remainingLen = (uint32_t) (comp + compLength - p);
return strbuf->length == remainingLen && memcmp(strbuf->chars, p, remainingLen) == 0;
}
uint32_t substrLength = (uint32_t) (colon - p);
@@ -817,9 +761,10 @@ bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength
}
for (const char* p = comp; p < comp + compLength;) {
const char* colon = memchr(p, separator, compLength);
if (colon == NULL) {
return strcasecmp(strbuf->chars, p) == 0;
const char* colon = memchr(p, separator, (size_t) (comp + compLength - p));
if (colon == nullptr) {
uint32_t remainingLen = (uint32_t) (comp + compLength - p);
return strbuf->length == remainingLen && strncasecmp(strbuf->chars, p, remainingLen) == 0;
}
uint32_t substrLength = (uint32_t) (colon - p);
+5 -2
View File
@@ -1,4 +1,5 @@
#include "common/base64.h"
#include "common/endian.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) {
@@ -6,7 +7,9 @@ void ffBase64EncodeRaw(uint32_t size, const char* str, uint32_t* out_size, char*
char* out = output;
const char* ends = str + (size - size % 3);
while (str != ends) {
uint32_t n = __builtin_bswap32(*(uint32_t*) str);
uint32_t n = *(uint32_t*) str;
// The 3 input bytes must be laid out big-endian (str[0] in the most significant position).
n = FF_READ_BE(n);
*out++ = chars[(n >> 26) & 63];
*out++ = chars[(n >> 20) & 63];
*out++ = chars[(n >> 14) & 63];
@@ -34,7 +37,7 @@ void ffBase64EncodeRaw(uint32_t size, const char* str, uint32_t* out_size, char*
static uint8_t decode_table[256];
void init_decode_table() {
static void init_decode_table() {
uint8_t ch = 0;
do {
int32_t code = -1;
+13 -14
View File
@@ -1,6 +1,6 @@
#include "common/binary.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include <string.h>
#include <fcntl.h>
@@ -20,7 +20,7 @@ typedef struct {
static inline void wrapMunmap(FFMemoryMapping* mapping) {
assert(mapping);
if (mapping->data == NULL || mapping->data == MAP_FAILED) {
if (mapping->data == nullptr || mapping->data == MAP_FAILED) {
return;
}
munmap((void*) mapping->data, mapping->length);
@@ -31,12 +31,12 @@ static inline void wrapMunmap(FFMemoryMapping* mapping) {
*/
static inline const void* readData(const FFMemoryMapping* mapping, size_t size, off_t offset) {
if (offset < 0) {
return NULL;
return nullptr;
}
size_t start = (size_t) offset;
if (start > mapping->length || size > mapping->length - start) {
return NULL;
return nullptr;
}
return mapping->data + start;
@@ -72,6 +72,7 @@ static bool handleMachSection(const FFMemoryMapping* mapping, const char* name,
}
uint32_t len = (uint32_t) strnlen(p, size - off);
if (len < minLength) {
off += len; // Skip short strings
continue;
}
if (*p >= ' ' && *p <= '~') { // Ignore control characters
@@ -98,7 +99,7 @@ static bool handleMachSection(const FFMemoryMapping* mapping, const char* name,
* @param userdata User data for the callback
* @param minLength Minimum string length to extract
*
* @return NULL on success, error message on failure
* @return nullptr on success, error message on failure
*/
static const char* dumpMachHeader(const FFMemoryMapping* mapping, off_t offset, bool is_64, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
uint32_t ncmds;
@@ -123,7 +124,7 @@ static const char* dumpMachHeader(const FFMemoryMapping* mapping, off_t offset,
}
off_t commandOffset = loadCommandsOffset;
const struct load_command* cmd = NULL;
const struct load_command* cmd = nullptr;
for (uint32_t i = 0U; i < ncmds; i++, commandOffset += cmd->cmdsize) {
cmd = readData(mapping, sizeof(*cmd), commandOffset);
if (!cmd) {
@@ -152,7 +153,7 @@ static const char* dumpMachHeader(const FFMemoryMapping* mapping, off_t offset,
}
if (!handleMachSection(mapping, section->sectname, (off_t) section->offset, (size_t) section->size, cb, userdata, minLength)) {
return NULL;
return nullptr;
}
}
} else if (cmd->cmd == LC_SEGMENT) {
@@ -173,15 +174,13 @@ static const char* dumpMachHeader(const FFMemoryMapping* mapping, off_t offset,
}
if (!handleMachSection(mapping, section->sectname, (off_t) section->offset, (size_t) section->size, cb, userdata, minLength)) {
return NULL;
return nullptr;
}
}
}
return NULL;
}
return NULL;
return nullptr;
}
/**
@@ -196,7 +195,7 @@ static const char* dumpMachHeader(const FFMemoryMapping* mapping, off_t offset,
* @param userdata User data for the callback
* @param minLength Minimum string length to extract
*
* @return NULL on success, error message on failure
* @return nullptr on success, error message on failure
*/
static const char* dumpFatHeader(const FFMemoryMapping* mapping, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
const struct fat_header* headerRaw = readData(mapping, sizeof(struct fat_header), 0);
@@ -274,8 +273,8 @@ const char* ffBinaryExtractStrings(const char* machoFile, bool (*cb)(const char*
return "Failed to stat file";
}
FF_A_CLEANUP(wrapMunmap) FFMemoryMapping mapping = {
.data = mmap(NULL, (size_t) st.st_size, PROT_READ, MAP_PRIVATE, fd, 0),
[[gnu::cleanup(wrapMunmap)]] FFMemoryMapping mapping = {
.data = mmap(nullptr, (size_t) st.st_size, PROT_READ, MAP_PRIVATE, fd, 0),
.length = (size_t) st.st_size,
};
if (mapping.data == MAP_FAILED) {
+16 -15
View File
@@ -4,7 +4,7 @@
#include "common/io.h"
#include "common/library.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include <libelf.h> // #1254
#include <fcntl.h>
@@ -56,10 +56,10 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_strptr)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_end)
libelf = NULL;
libelf = nullptr;
}
if (elfData.ffelf_end == NULL) {
if (elfData.ffelf_end == nullptr) {
return "load libelf failed";
}
@@ -69,8 +69,8 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
return "open() failed";
}
Elf* elf = elfData.ffelf_begin(fd, ELF_C_READ, NULL);
if (elf == NULL) {
Elf* elf = elfData.ffelf_begin(fd, ELF_C_READ, nullptr);
if (elf == nullptr) {
return "elf_begin() failed";
}
@@ -82,27 +82,27 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
}
// Iterate through all sections, looking for .rodata which contains string literals
Elf_Scn* scn = NULL;
while ((scn = elfData.ffelf_nextscn(elf, scn)) != NULL) {
Elf_Scn* scn = nullptr;
while ((scn = elfData.ffelf_nextscn(elf, scn)) != nullptr) {
// Try 64-bit section header first, then 32-bit if that fails
Elf64_Shdr* shdr64 = elfData.ffelf64_getshdr(scn);
Elf32_Shdr* shdr32 = NULL;
if (shdr64 == NULL) {
Elf32_Shdr* shdr32 = nullptr;
if (shdr64 == nullptr) {
shdr32 = elfData.ffelf32_getshdr(scn);
if (shdr32 == NULL) {
if (shdr32 == nullptr) {
continue;
}
}
// Get the section name and check if it's .rodata
const char* name = elfData.ffelf_strptr(elf, shstrndx, shdr64 ? shdr64->sh_name : shdr32->sh_name);
if (name == NULL || !ffStrEquals(name, ".rodata")) {
if (name == nullptr || !ffStrEquals(name, ".rodata")) {
continue;
}
// Get the section data
Elf_Data* data = elfData.ffelf_getdata(scn, NULL);
if (data == NULL) {
Elf_Data* data = elfData.ffelf_getdata(scn, nullptr);
if (data == nullptr) {
continue;
}
@@ -112,8 +112,9 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
if (*p == '\0') {
continue;
}
uint32_t len = (uint32_t) strlen(p);
uint32_t len = (uint32_t) strnlen(p, data->d_size - off);
if (len < minLength) {
off += len;
continue;
}
// Only process printable ASCII characters
@@ -130,7 +131,7 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
}
elfData.ffelf_end(elf);
return NULL;
return nullptr;
}
#else
+9 -8
View File
@@ -1,6 +1,6 @@
#include "common/binary.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "common/windows/nt.h"
#include <windows.h>
@@ -15,19 +15,19 @@
* Each string found is passed to the callback function for processing.
*/
const char* ffBinaryExtractStrings(const char* peFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata, uint32_t minLength) {
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);
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileA(peFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
return "CreateFileA() failed";
}
FF_AUTO_CLOSE_FD HANDLE hSection = NULL;
if (!NT_SUCCESS(NtCreateSection(&hSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, hFile))) {
FF_AUTO_CLOSE_FD HANDLE hSection = nullptr;
if (!NT_SUCCESS(NtCreateSection(&hSection, SECTION_MAP_READ, nullptr, nullptr, PAGE_READONLY, SEC_COMMIT, hFile))) {
return "NtCreateSection() failed";
}
PVOID base = NULL;
PVOID base = nullptr;
SIZE_T viewSize = 0;
if (!NT_SUCCESS(NtMapViewOfSection(hSection, NtCurrentProcess(), &base, 0, 0, NULL, &viewSize, ViewUnmap, 0, PAGE_READONLY))) {
if (!NT_SUCCESS(NtMapViewOfSection(hSection, NtCurrentProcess(), &base, 0, 0, nullptr, &viewSize, ViewUnmap, 0, PAGE_READONLY))) {
return "NtMapViewOfSection() failed";
}
@@ -49,8 +49,9 @@ const char* ffBinaryExtractStrings(const char* peFile, bool (*cb)(const char* st
if (*p == '\0') {
continue;
}
uint32_t len = (uint32_t) strlen(p);
uint32_t len = (uint32_t) strnlen(p, section->SizeOfRawData - off);
if (len < minLength) {
off += len;
continue;
}
// Only process printable ASCII characters
@@ -66,5 +67,5 @@ const char* ffBinaryExtractStrings(const char* peFile, bool (*cb)(const char* st
}
NtUnmapViewOfSection(NtCurrentProcess(), base);
return NULL;
return nullptr;
}
+86 -28
View File
@@ -3,7 +3,7 @@
#include "common/printing.h"
#include "common/time.h"
#include "common/jsonconfig.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "fastfetch_datatext.h"
#include "modules/modules.h"
@@ -15,12 +15,12 @@ bool ffParseModuleOptions(const char* key, const char* value) {
return false;
}
if (value && !*value) {
value = NULL;
value = nullptr;
}
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules) {
FFModuleBaseInfo* baseInfo = *modules;
const char* subKey = ffOptionTestPrefix(key, baseInfo->name);
if (subKey != NULL) {
if (subKey != nullptr) {
if (subKey[0] == '\0' || subKey[0] == '-') // Key is exactly the module name or has a leading '-'
{
fprintf(stderr, "Error: unknown module key %s\n", key);
@@ -64,53 +64,74 @@ bool ffParseModuleOptions(const char* key, const char* value) {
}
void ffPrepareCommandOption(FFdata* data) {
char* moduleType = NULL;
char* moduleType = nullptr;
size_t moduleLen = 0;
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) {
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (moduleLen == strlen(moduleNameConstant) && ffStrEqualsIgnCase(moduleType, moduleNameConstant) && !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (ffStrEqualsIgnCase(moduleType, moduleNameConstant) && !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
switch (moduleType[0]) {
#if !FF_MODULE_DISABLE_CPUUSAGE
case 'C':
case 'c':
FF_IF_MODULE_MATCH(FF_CPUUSAGE_MODULE_NAME)
FF_IF_MODULE_MATCH(ffCPUUsageModuleInfo.name)
ffPrepareCPUUsage();
break;
#endif
#if !FF_MODULE_DISABLE_DISKIO
case 'D':
case 'd':
FF_IF_MODULE_MATCH(FF_DISKIO_MODULE_NAME) {
FF_A_CLEANUP(ffDestroyDiskIOOptions) FFDiskIOOptions options;
FF_IF_MODULE_MATCH(ffDiskIOModuleInfo.name) {
[[gnu::cleanup(ffDestroyDiskIOOptions)]] FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
ffPrepareDiskIO(&options);
}
break;
#endif
#if !FF_MODULE_DISABLE_NETIO
case 'N':
case 'n':
FF_IF_MODULE_MATCH(FF_NETIO_MODULE_NAME) {
FF_A_CLEANUP(ffDestroyNetIOOptions) FFNetIOOptions options;
FF_IF_MODULE_MATCH(ffNetIOModuleInfo.name) {
[[gnu::cleanup(ffDestroyNetIOOptions)]] FFNetIOOptions options;
ffInitNetIOOptions(&options);
ffPrepareNetIO(&options);
}
break;
#endif
#if !FF_MODULE_DISABLE_PUBLICIP
case 'P':
case 'p':
FF_IF_MODULE_MATCH(FF_PUBLICIP_MODULE_NAME) {
FF_A_CLEANUP(ffDestroyPublicIpOptions) FFPublicIPOptions options;
FF_IF_MODULE_MATCH(ffPublicIPModuleInfo.name) {
[[gnu::cleanup(ffDestroyPublicIpOptions)]] FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
break;
#endif
#if !FF_MODULE_DISABLE_TOP
case 'T':
case 't':
FF_IF_MODULE_MATCH(ffTopModuleInfo.name) {
[[gnu::cleanup(ffDestroyTopOptions)]] FFTopOptions options;
ffInitTopOptions(&options);
ffPrepareTopProcesses(options.showTypes);
}
break;
#endif
#if !FF_MODULE_DISABLE_WEATHER
case 'W':
case 'w':
FF_IF_MODULE_MATCH(FF_WEATHER_MODULE_NAME) {
FF_A_CLEANUP(ffDestroyWeatherOptions) FFWeatherOptions options;
FF_IF_MODULE_MATCH(ffWeatherModuleInfo.name) {
[[gnu::cleanup(ffDestroyWeatherOptions)]] FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
}
break;
#endif
}
#undef FF_IF_MODULE_MATCH
@@ -157,7 +178,35 @@ static void genJsonResult(FFdata* data, FFModuleBaseInfo* baseInfo, void* option
}
}
static void parseStructureCommand(
static yyjson_val* findStructureModuleConfig(FFdata* data, const char* moduleType) {
if (data->configDoc == nullptr) {
return nullptr;
}
yyjson_val* root = yyjson_doc_get_root(data->configDoc);
if (root == nullptr) {
return nullptr;
}
yyjson_val* modules = yyjson_obj_get(root, "modules");
if (!yyjson_is_arr(modules)) {
return nullptr;
}
yyjson_val* item;
size_t idx, max;
yyjson_arr_foreach (modules, idx, max, item) {
if (yyjson_is_obj(item)) {
const char* type = yyjson_get_str(yyjson_obj_get(item, "type"));
if (type != nullptr && ffStrEqualsIgnCase(type, moduleType)) {
return item;
}
}
}
return nullptr;
}
static bool parseStructureCommand(
FFdata* data,
const char* line,
void (*fn)(FFdata*, FFModuleBaseInfo* baseInfo, void* options)) {
@@ -165,27 +214,41 @@ static void parseStructureCommand(
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(line[0]) - 'A']; *modules; ++modules) {
FFModuleBaseInfo* baseInfo = *modules;
if (ffStrEqualsIgnCase(line, baseInfo->name)) {
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
alignas(uint64_t) uint8_t optionBuf[FF_OPTION_MAX_SIZE];
baseInfo->initOptions(optionBuf);
if (__builtin_expect(data->resultDoc != NULL, false)) {
if (data->resultDoc != nullptr) {
fn(data, baseInfo, optionBuf);
} else {
baseInfo->printModule(optionBuf);
yyjson_val* configModule = findStructureModuleConfig(data, baseInfo->name);
if (configModule != nullptr) {
baseInfo->parseJsonObject(optionBuf, configModule);
baseInfo->printModule(optionBuf);
} else {
baseInfo->printModule(optionBuf);
}
}
baseInfo->destroyOptions(optionBuf);
return;
return true;
}
}
}
ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
if (data->resultDoc) {
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", line);
yyjson_mut_obj_add_str(doc, module, "error", "Unknown module type");
} else {
ffPrintError(line, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
}
return false;
}
void ffPrintCommandOption(FFdata* data) {
// Parse the structure and call the modules
int32_t thres = instance.config.display.stat;
char* moduleType = NULL;
char* moduleType = nullptr;
size_t moduleLen = 0;
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) {
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':')) {
@@ -213,7 +276,7 @@ void ffPrintCommandOption(FFdata* data) {
: FF_COLOR_FG_RED),
ms);
}
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len - 1, str); // Save; Up 1; Right 9999999; Left <len - 1>; Print <str>; Load
}
}
@@ -226,12 +289,7 @@ void ffPrintCommandOption(FFdata* data) {
}
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
}
char* moduleType = NULL;
char* moduleType = nullptr;
size_t moduleLen = 0;
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure)) {
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':')) {
+69 -24
View File
@@ -3,7 +3,7 @@
#ifdef FF_HAVE_DBUS
#include "common/thread.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
static bool loadLibSymbols(FFDBusLibrary* lib) {
FF_LIBRARY_LOAD(dbus, false, "libdbus-1" FF_LIBRARY_EXTENSION, 4);
@@ -19,7 +19,7 @@ static bool loadLibSymbols(FFDBusLibrary* lib) {
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
dbus = nullptr; // don't auto dlclose
return true;
}
@@ -33,27 +33,27 @@ static const FFDBusLibrary* loadLib(void) {
loadSuccess = loadLibSymbols(&lib);
}
return loadSuccess ? &lib : NULL;
return loadSuccess ? &lib : nullptr;
}
const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data) {
data->lib = loadLib();
if (data->lib == NULL) {
if (data->lib == nullptr) {
return "Failed to load DBus library";
}
data->connection = data->lib->ffdbus_bus_get(busType, NULL);
if (data->connection == NULL) {
data->connection = data->lib->ffdbus_bus_get(busType, nullptr);
if (data->connection == nullptr) {
return "Failed to connect to DBus";
}
return NULL;
return nullptr;
}
void ffDBusDestroyData(FFDBusData* data) {
if (data->connection != NULL) {
if (data->connection != nullptr) {
data->lib->ffdbus_connection_unref(data->connection);
data->connection = NULL;
data->connection = nullptr;
}
}
@@ -61,7 +61,7 @@ bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
if (argType == DBUS_TYPE_STRING || argType == DBUS_TYPE_OBJECT_PATH) {
const char* value = NULL;
const char* value = nullptr;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
if (!ffStrSet(value)) {
@@ -76,7 +76,7 @@ bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
uint8_t value;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
ffStrbufAppendC(result, (char) value);
return false; // Don't append a comma
return true;
}
if (argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) {
@@ -92,6 +92,25 @@ bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
// At this point we have an array
int subArgType = dbus->lib->ffdbus_message_iter_get_arg_type(&subIter);
if (subArgType == DBUS_TYPE_INVALID) {
return false;
}
if (subArgType == DBUS_TYPE_BYTE) {
while (true) {
uint8_t value;
dbus->lib->ffdbus_message_iter_get_basic(&subIter, &value);
ffStrbufAppendC(result, (char) value);
if (!dbus->lib->ffdbus_message_iter_next(&subIter)) {
break;
}
}
return true;
}
bool foundAValue = false;
while (true) {
@@ -133,7 +152,7 @@ bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result) {
return ffDBusGetBool(dbus, &subIter, result);
}
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result) {
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint64_t* result) {
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
if (argType == DBUS_TYPE_BYTE) {
@@ -151,6 +170,13 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result) {
}
if (argType == DBUS_TYPE_UINT32) {
uint32_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = value;
return true;
}
if (argType == DBUS_TYPE_UINT64) {
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
return true;
}
@@ -164,7 +190,7 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result) {
return ffDBusGetUint(dbus, &subIter, result);
}
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) {
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int64_t* result) {
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
if (argType == DBUS_TYPE_INT16) {
@@ -175,6 +201,13 @@ bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) {
}
if (argType == DBUS_TYPE_INT32) {
int32_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = value;
return true;
}
if (argType == DBUS_TYPE_INT64) {
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
return true;
}
@@ -189,12 +222,24 @@ bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) {
if (argType == DBUS_TYPE_UINT16) {
uint16_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = (int16_t) value;
*result = (int32_t) value;
return true;
}
if (argType == DBUS_TYPE_UINT32) {
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
uint32_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
*result = (int32_t) value;
return true;
}
if (argType == DBUS_TYPE_UINT64) {
uint64_t value = 0;
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
if (value > INT64_MAX) {
return false;
}
*result = (int64_t) value;
return true;
}
@@ -209,8 +254,8 @@ bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) {
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2) {
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
if (message == NULL) {
return NULL;
if (message == nullptr) {
return nullptr;
}
if (arg1) {
@@ -221,7 +266,7 @@ DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const c
}
}
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL);
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, nullptr);
dbus->lib->ffdbus_message_unref(message);
@@ -230,8 +275,8 @@ DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const c
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property) {
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get");
if (message == NULL) {
return NULL;
if (message == nullptr) {
return nullptr;
}
dbus->lib->ffdbus_message_append_args(message,
@@ -241,7 +286,7 @@ DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char
&property,
DBUS_TYPE_INVALID);
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL);
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, nullptr);
dbus->lib->ffdbus_message_unref(message);
@@ -250,7 +295,7 @@ 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) {
DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
if (reply == NULL) {
if (reply == nullptr) {
return false;
}
@@ -267,9 +312,9 @@ bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char*
return ret;
}
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result) {
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint64_t* result) {
DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
if (reply == NULL) {
if (reply == nullptr) {
return false;
}
+7 -2
View File
@@ -2,6 +2,7 @@
#include "common/windows/nt.h"
#include <windows.h>
#include <cfgmgr32.h>
const char* ffDebugWin32Error(DWORD errorCode) {
static char buffer[512];
@@ -9,12 +10,12 @@ const char* ffDebugWin32Error(DWORD errorCode) {
wchar_t bufferW[256];
ULONG len = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
nullptr,
(DWORD) errorCode,
0,
bufferW,
ARRAY_SIZE(bufferW),
NULL);
nullptr);
if (len == 0) {
snprintf(buffer, sizeof(buffer), "Unknown error code (%lu)", errorCode);
@@ -34,6 +35,10 @@ const char* ffDebugWin32Error(DWORD errorCode) {
return buffer;
}
const char* ffDebugConfigRet(CONFIGRET ret) {
return ffDebugWin32Error(CM_MapCrToWin32Err(ret, ERROR_INTERNAL_ERROR));
}
const char* ffDebugNtStatus(NTSTATUS status) {
return ffDebugWin32Error(RtlNtStatusToDosError(status));
}
+43 -2
View File
@@ -66,7 +66,7 @@ void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* h
}
}
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week) {
void ffEdidGetManufactureDate(const uint8_t edid[128], uint16_t* year, uint16_t* week) {
if (edid[17] > 0 && edid[17] < 0xFF) {
*year = (uint16_t) (edid[17] + 1990);
*week = (uint16_t) edid[16];
@@ -76,8 +76,49 @@ void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial
} else {
*year = *week = 0;
}
}
*serial = *(uint32_t*) &edid[12];
bool ffEdidGetSerial(const uint8_t edid[128], FFstrbuf* result) {
int descriptor_offsets[4] = {54, 72, 90, 108};
for (int i = 0; i < 4; i++) {
int offset = descriptor_offsets[i];
const uint8_t* desc = edid + offset;
if (desc[0] == 0x00 && desc[1] == 0x00) { // Monitor Descriptor
uint8_t tag = desc[3]; // Descriptor Type Tag
if (tag == 0xFF) { // Display Product Serial Number
ffStrbufClear(result);
for (int j = 0; j < 13; j++) {
uint8_t ch = desc[5 + j];
if (ch == 0x0A || ch == 0x00) {
break;
}
ffStrbufAppendC(result, (char) ch);
}
ffStrbufTrim(result, ' ');
if (result->length > 0) {
return true;
}
}
}
}
uint32_t int_serial = 0;
int_serial |= (uint32_t)edid[12];
int_serial |= (uint32_t)edid[13] << 8;
int_serial |= (uint32_t)edid[14] << 16;
int_serial |= (uint32_t)edid[15] << 24;
if (int_serial != 0 && int_serial != 0xFFFFFFFF) {
ffStrbufSetF(result, "0x%08X", int_serial);
return true;
}
return false;
}
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length) {
+15 -10
View File
@@ -1,7 +1,7 @@
#include "fastfetch.h"
#include "common/FFlist.h"
#include "common/FFstrbuf.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "common/font.h"
#include <string.h>
@@ -16,7 +16,7 @@ void ffFontInit(FFfont* font) {
}
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude) {
if (value == NULL || length == 0) {
if (value == nullptr || length == 0) {
return;
}
@@ -151,7 +151,7 @@ static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* altern
ffStrStartsWithIgnCase(wordStart, "Black") ||
ffStrStartsWithIgnCase(wordStart, "Condensed") ||
ffStrStartsWithIgnCase(wordStart, "Expanded")) {
if (alternativeBuffer == NULL) {
if (alternativeBuffer == nullptr) {
alternativeBuffer = FF_LIST_ADD(FFstrbuf, font->styles);
ffStrbufInit(alternativeBuffer);
}
@@ -169,7 +169,7 @@ static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* altern
return;
}
if (alternativeBuffer != NULL) {
if (alternativeBuffer != nullptr) {
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
return;
}
@@ -184,7 +184,7 @@ void ffFontInitPango(FFfont* font, const char* data) {
ffFontInit(font);
while (*data != '\0' && *data != '`' && *data != '\\') {
fontPangoParseWord(&data, font, NULL);
fontPangoParseWord(&data, font, nullptr);
}
fontInitPretty(font);
@@ -329,8 +329,8 @@ void ffFontInitXft(FFfont* font, const char* xft) {
}
// Try parse trailing "-<number>" as size, otherwise entire head is name
const char* dashPos = NULL;
const char* sizeStart = NULL;
const char* dashPos = nullptr;
const char* sizeStart = nullptr;
for (const char* q = headEnd; q > headStart;) {
--q;
@@ -425,10 +425,11 @@ void ffFontInitXft(FFfont* font, const char* xft) {
if (value.length > 0) {
if (
(keyLen == 4 && ffStrStartsWithIgnCase(keyStart, "size")) ||
(keyLen == 9 && ffStrStartsWithIgnCase(keyStart, "pixelsize"))) {
(keyLen == 9 && (ffStrStartsWithIgnCase(keyStart, "pixelsize") || ffStrStartsWithIgnCase(keyStart, "pointsize")))) {
if (sizeEmpty && ffCharIsDigit(value.chars[0])) {
ffStrbufAppend(&font->size, &value);
ffStrbufAppendS(&font->size, keyLen == 4 ? "pt" : "px");
ffStrbufAppendS(&font->size,
(keyLen == 9 && ffStrStartsWithIgnCase(keyStart, "pixelsize")) ? "px" : "pt");
}
} else if (keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "style")) {
// style may contain multiple words: "Bold Italic"
@@ -457,6 +458,10 @@ void ffFontInitXft(FFfont* font, const char* xft) {
ffStrbufInit(style);
strbufAppendNSExcludingC(style, value.length, value.chars, '-');
ffStrbufTrim(style, ' ');
if (style->length == 0) {
ffStrbufDestroy(style);
--font->styles.length;
}
}
}
}
@@ -483,7 +488,7 @@ void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf
void ffFontInitWithSpace(FFfont* font, const char* rawName) {
const char* pspace = strrchr(rawName, ' ');
if (pspace == NULL) {
if (pspace == nullptr) {
ffFontInitCopy(font, rawName);
return;
}
+408 -11
View File
@@ -2,7 +2,8 @@
#include "common/format.h"
#include "common/parsing.h"
#include "common/textModifier.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "common/library.h"
#include <inttypes.h>
@@ -77,7 +78,7 @@ static uint32_t getArgumentIndex(const char* placeholderValue, uint32_t numArgs,
}
if (firstChar >= '0' && firstChar <= '9') {
char* pEnd = NULL;
char* pEnd = nullptr;
uint32_t result = (uint32_t) strtoul(placeholderValue, &pEnd, 10);
if (result > numArgs) {
return UINT32_MAX;
@@ -108,10 +109,363 @@ static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start,
}
static inline bool formatArgSet(const FFformatarg* arg) {
return arg->value != NULL && ((arg->type == FF_ARG_TYPE_DOUBLE && *(double*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_FLOAT && *(float*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_INT && *(int*) arg->value > 0) || (arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*) arg->value)->length > 0) || (arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*) arg->value)) || (arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT && *(uint32_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_BOOL && *(bool*) arg->value) || (arg->type == FF_ARG_TYPE_LIST && ((FFlist*) arg->value)->length > 0));
// clang-format off
return arg->value != nullptr && (
(arg->type == FF_ARG_TYPE_DOUBLE && *(double*) arg->value > 0.0) ||
(arg->type == FF_ARG_TYPE_FLOAT && *(float*) arg->value > 0.0) ||
(arg->type == FF_ARG_TYPE_INT && *(int32_t*) arg->value > 0) ||
(arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*) arg->value)->length > 0) ||
(arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*) arg->value)) ||
(arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*) arg->value > 0) ||
(arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*) arg->value > 0) ||
(arg->type == FF_ARG_TYPE_UINT && *(uint32_t*) arg->value > 0) ||
(arg->type == FF_ARG_TYPE_UINT64 && *(uint64_t*) arg->value > 0) ||
(arg->type == FF_ARG_TYPE_BOOL && *(bool*) arg->value) ||
(arg->type == FF_ARG_TYPE_LIST && ((FFlist*) arg->value)->length > 0)
);
// clang-format on
}
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
[[maybe_unused]] static inline void normalizeArgName(FFstrbuf* dst, const char* src) {
ffStrbufClear(dst);
bool flag = false;
for (const char* p = src; *p; ++p) {
if (*p == '-') {
flag = true;
} else if (flag) {
ffStrbufAppendC(dst, (char) toupper((unsigned char) *p));
flag = false;
} else {
ffStrbufAppendC(dst, *p);
}
}
}
#if FF_HAVE_LUA
#include "common/lua.h"
static void appendLuaError(FFstrbuf* buffer, const char* prefix, lua_State* L) {
const char* err = lua_tolstring(L, -1, nullptr);
if (err) {
const char* tmp = strchr(err, ':');
if (tmp) {
err = tmp + 1;
while (*err == ' ') {
++err;
}
}
}
ffStrbufAppendF(buffer, "%s: %s", prefix, err ? err : "unknown");
}
static bool parseLuaString(FFstrbuf* buffer, const char* script, uint32_t scriptLen, uint32_t numArgs, const FFformatarg* arguments) {
const char* err = ffLuaLoadState();
if (err) {
ffStrbufAppendF(buffer, "Lua init error: %s", err);
return false;
}
FF_STRBUF_AUTO_DESTROY argNameBuf = ffStrbufCreate();
bool ret = false;
lua_State* L = luaData.L;
// Clear stack and load chunk
lua_settop(L, 0);
if (luaL_loadbuffer(L, script, scriptLen, "") != LUA_OK) {
appendLuaError(buffer, "Lua load error", L);
} else {
// Build args table for name lookup only.
lua_createtable(L, 0, 0);
for (uint32_t i = 0; i < numArgs; ++i) {
const FFformatarg* arg = &arguments[i];
switch (arg->type) {
case FF_ARG_TYPE_INT:
lua_pushinteger(L, (lua_Integer) * (int32_t*) arg->value);
break;
case FF_ARG_TYPE_UINT:
lua_pushinteger(L, (lua_Integer) * (uint32_t*) arg->value);
break;
case FF_ARG_TYPE_UINT64:
lua_pushinteger(L, (lua_Integer) * (uint64_t*) arg->value);
break;
case FF_ARG_TYPE_UINT16:
lua_pushinteger(L, (lua_Integer) * (uint16_t*) arg->value);
break;
case FF_ARG_TYPE_UINT8:
lua_pushinteger(L, (lua_Integer) * (uint8_t*) arg->value);
break;
case FF_ARG_TYPE_FLOAT:
lua_pushnumber(L, (lua_Number) * (float*) arg->value);
break;
case FF_ARG_TYPE_DOUBLE:
lua_pushnumber(L, (lua_Number) * (double*) arg->value);
break;
case FF_ARG_TYPE_BOOL:
lua_pushboolean(L, *(bool*) arg->value);
break;
case FF_ARG_TYPE_STRING:
lua_pushlstring(L, (const char*) arg->value, strlen((const char*) arg->value));
break;
case FF_ARG_TYPE_STRBUF: {
const FFstrbuf* sb = (const FFstrbuf*) arg->value;
lua_pushlstring(L, sb->chars, sb->length);
break;
}
case FF_ARG_TYPE_LIST: {
const FFlist* list = (const FFlist*) arg->value;
lua_createtable(L, 0, 0);
for (uint32_t li = 0; li < list->length; ++li) {
const FFstrbuf* item = FF_LIST_GET(FFstrbuf, *list, li);
lua_pushlstring(L, item->chars, item->length);
lua_seti(L, -2, (lua_Integer) (li + 1));
}
break;
}
default:
lua_pushnil(L);
break;
}
if (arg->name && arg->name[0]) {
normalizeArgName(&argNameBuf, arg->name);
} else {
ffStrbufSetF(&argNameBuf, "arg%" PRIu32, i + 1);
}
lua_setfield(L, -2, argNameBuf.chars);
}
if (lua_pcall(L, 1, LUA_MULTRET, 0) != LUA_OK) {
appendLuaError(buffer, "Lua runtime error", L);
} else {
int nresults = lua_gettop(L);
if (nresults == 0) {
ffStrbufAppendS(buffer, "Lua result error: no result");
} else {
// Convert first result to string
const char* res = lua_tolstring(L, 1, nullptr);
if (res) {
ffStrbufAppendS(buffer, res);
} else {
luaL_tolstring(L, 1, nullptr);
const char* sval = lua_tolstring(L, -1, nullptr);
if (sval) {
ffStrbufAppendS(buffer, sval);
}
}
ret = true;
}
}
}
lua_settop(L, 0);
return ret;
}
#endif
#if FF_HAVE_QUICKJS
#include <quickjs.h>
struct FFQuickJSData {
FF_LIBRARY_SYMBOL(JS_NewRuntime)
FF_LIBRARY_SYMBOL(JS_NewContext)
FF_LIBRARY_SYMBOL(JS_FreeRuntime)
FF_LIBRARY_SYMBOL(JS_EvalThis)
FF_LIBRARY_SYMBOL(JS_GetException)
FF_LIBRARY_SYMBOL(JS_ToCStringLen2)
FF_LIBRARY_SYMBOL(JS_FreeCString)
FF_LIBRARY_SYMBOL(JS_NewStringLen)
FF_LIBRARY_SYMBOL(JS_NewArray)
FF_LIBRARY_SYMBOL(JS_NewBigUint64)
FF_LIBRARY_SYMBOL(JS_SetPropertyUint32)
FF_LIBRARY_SYMBOL(JS_NewObject)
FF_LIBRARY_SYMBOL(JS_SetPropertyStr)
FF_LIBRARY_SYMBOL(JS_FreeValue)
JSRuntime* rt;
JSContext* ctx;
bool inited;
} qjsData;
static const char* loadQuickJSState(void) {
if (qjsData.inited) {
if (qjsData.ctx == nullptr) {
return "QuickJS is not available";
}
return nullptr;
}
qjsData.inited = true;
#ifdef _WIN32
FF_LIBRARY_LOAD_MESSAGE(libqjs, "libqjs-0" FF_LIBRARY_EXTENSION, 0)
#else
FF_LIBRARY_LOAD_MESSAGE(libqjs, "libqjs" FF_LIBRARY_EXTENSION, 0)
#endif
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewRuntime)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewContext)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_FreeRuntime)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_EvalThis)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_GetException)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_ToCStringLen2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_FreeCString)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewStringLen)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewArray)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_SetPropertyUint32)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewObject)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_SetPropertyStr)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_FreeValue)
qjsData.rt = qjsData.ffJS_NewRuntime();
if (qjsData.rt == nullptr) {
return "JS_NewRuntime() failed";
}
qjsData.ctx = qjsData.ffJS_NewContext(qjsData.rt);
if (qjsData.ctx == nullptr) {
qjsData.ffJS_FreeRuntime(qjsData.rt);
qjsData.rt = nullptr;
return "JS_NewContext() failed";
}
libqjs = nullptr; // don't close quickjs
return nullptr;
}
static bool parseQuickJSString(FFstrbuf* buffer, const char* script, uint32_t scriptLen, uint32_t numArgs, const FFformatarg* arguments) {
const char* err = loadQuickJSState();
if (err) {
ffStrbufAppendF(buffer, "Qjs init error: %s", err);
return false;
}
JSContext* ctx = qjsData.ctx;
JSValue argsObj = qjsData.ffJS_NewObject(ctx);
FF_STRBUF_AUTO_DESTROY argNameBuf = ffStrbufCreate();
for (uint32_t i = 0; i < numArgs; ++i) {
const FFformatarg* arg = &arguments[i];
JSValue value;
switch (arg->type) {
case FF_ARG_TYPE_INT:
value = JS_NewInt32(ctx, *(int32_t*) arg->value);
break;
case FF_ARG_TYPE_UINT:
value = JS_NewUint32(ctx, *(uint32_t*) arg->value);
break;
case FF_ARG_TYPE_UINT64: {
uint64_t val = *(uint64_t*) arg->value;
if (val <= INT32_MAX) {
value = JS_NewInt32(ctx, (int32_t) val);
} else {
value = JS_NewFloat64(ctx, (double) val);
}
break;
}
case FF_ARG_TYPE_UINT16:
value = JS_NewUint32(ctx, *(uint16_t*) arg->value);
break;
case FF_ARG_TYPE_UINT8:
value = JS_NewUint32(ctx, *(uint8_t*) arg->value);
break;
case FF_ARG_TYPE_FLOAT:
value = JS_NewFloat64(ctx, *(float*) arg->value);
break;
case FF_ARG_TYPE_DOUBLE:
value = JS_NewFloat64(ctx, *(double*) arg->value);
break;
case FF_ARG_TYPE_BOOL:
value = JS_NewBool(ctx, *(bool*) arg->value);
break;
case FF_ARG_TYPE_STRING:
value = qjsData.ffJS_NewStringLen(ctx, (const char*) arg->value, strlen((const char*) arg->value));
break;
case FF_ARG_TYPE_STRBUF: {
const FFstrbuf* sb = (const FFstrbuf*) arg->value;
value = qjsData.ffJS_NewStringLen(ctx, sb->chars, sb->length);
break;
}
case FF_ARG_TYPE_LIST: {
const FFlist* list = (const FFlist*) arg->value;
JSValue arr = qjsData.ffJS_NewArray(ctx);
for (uint32_t li = 0; li < list->length; ++li) {
const FFstrbuf* item = FF_LIST_GET(FFstrbuf, *list, li);
JSValue itemValue = qjsData.ffJS_NewStringLen(ctx, item->chars, item->length);
qjsData.ffJS_SetPropertyUint32(ctx, arr, li, itemValue);
}
value = arr;
break;
}
default:
value = JS_UNDEFINED;
break;
}
if (arg->name && arg->name[0]) {
normalizeArgName(&argNameBuf, arg->name);
} else {
ffStrbufSetF(&argNameBuf, "arg%" PRIu32, i + 1);
}
qjsData.ffJS_SetPropertyStr(ctx, argsObj, argNameBuf.chars, value);
}
JSValue result = qjsData.ffJS_EvalThis(ctx, argsObj, script, scriptLen, "", JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_STRICT);
qjsData.ffJS_FreeValue(ctx, argsObj);
bool ret = false;
if (JS_IsException(result)) {
JSValue exc = qjsData.ffJS_GetException(ctx);
const char* message = qjsData.ffJS_ToCStringLen2(ctx, nullptr, exc, false);
qjsData.ffJS_FreeValue(ctx, exc);
ffStrbufAppendF(buffer, "Qjs runtime error: %s", message ?: "unknown");
if (message) {
qjsData.ffJS_FreeCString(ctx, message);
}
} else if (JS_IsUndefined(result)) {
ffStrbufAppendS(buffer, "Qjs result error: undefined result");
} else {
size_t len;
const char* res = qjsData.ffJS_ToCStringLen2(ctx, &len, result, false);
if (res) {
ffStrbufAppendNS(buffer, (uint32_t) len, res);
qjsData.ffJS_FreeCString(ctx, res);
}
ret = true;
}
qjsData.ffJS_FreeValue(ctx, result);
return ret;
}
#endif
static bool skipAnsiEscape(FFstrbuf* in, FFstrbuf* out, FFstrbuf* trailingEscape) {
if (__builtin_expect(in->chars[0] == '\e' && in->chars[1] == '[', false)) {
// skip ANSI escape codes at the start of the string for truncation
const char* p = in->chars + 2;
while (*p && (ffCharIsDigit(*p) || *p == ';')) {
++p;
}
if (*p && isascii(*p)) {
++p;
}
uint32_t prefixLen = (uint32_t) (p - in->chars);
ffStrbufAppendNS(out, prefixLen, in->chars);
ffStrbufSubstrAfter(in, prefixLen - 1);
if (trailingEscape) {
// likely have a `CSI m` reset at the end of the string
uint32_t iLastEscape = ffStrbufLastIndexC(in, '\e');
if (iLastEscape != in->length) {
ffStrbufSetNS(trailingEscape, in->length - iLastEscape, in->chars + iLastEscape);
ffStrbufSubstrBefore(in, iLastEscape);
}
}
return true;
}
return false;
}
static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
uint32_t argCounter = 0;
uint32_t numOpenIfs = 0;
@@ -129,6 +483,12 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
// jump to next char, the start of the placeholder value
++i;
// unmatched trailing '{'
if (i >= formatstr->length) {
ffStrbufAppendC(buffer, '{');
break;
}
// double {{ elvaluates to a single { and doesn't count as start
if (formatstr->chars[i] == '{') {
ffStrbufAppendC(buffer, '{');
@@ -241,7 +601,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
// test for constant or env var, if so evaluate it
if (firstChar == '$') {
char* pend = NULL;
char* pend = nullptr;
int32_t indexSigned = (int32_t) strtol(placeholderValue.chars + 1, &pend, 10);
if (pend == placeholderValue.chars + 1) {
// treat placeholder as an environment variable
@@ -267,14 +627,14 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
char* pSep = placeholderValue.chars;
char cSep = '\0';
while (*pSep && *pSep != ':' && *pSep != '<' && *pSep != '>' && *pSep != '~') {
while (*pSep && *pSep != ':' && *pSep != '<' && *pSep != '>' && *pSep != '|' && *pSep != '~') {
++pSep;
}
if (*pSep) {
cSep = *pSep;
*pSep = '\0';
} else {
pSep = NULL;
pSep = nullptr;
}
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
@@ -297,8 +657,10 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
} else if (cSep == '~') {
FF_STRBUF_AUTO_DESTROY tempString = ffStrbufCreate();
ffFormatAppendFormatArg(&tempString, &arguments[index - 1]);
FF_STRBUF_AUTO_DESTROY trailingEscape = ffStrbufCreate();
skipAnsiEscape(&tempString, buffer, &trailingEscape);
char* pEnd = NULL;
char* pEnd = nullptr;
int32_t start = (int32_t) strtol(pSep + 1, &pEnd, 10);
if (start < 0) {
start = (int32_t) tempString.length + start;
@@ -322,13 +684,17 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
}
}
if (trailingEscape.length > 0) {
ffStrbufAppend(buffer, &trailingEscape);
}
if (*pEnd) {
*pSep = cSep;
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
continue;
}
} else {
char* pEnd = NULL;
char* pEnd = nullptr;
int32_t truncLength = (int32_t) strtol(pSep + 1, &pEnd, 10);
if (*pEnd != '\0') {
*pSep = cSep;
@@ -344,6 +710,9 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
FF_STRBUF_AUTO_DESTROY tempString = ffStrbufCreate();
ffFormatAppendFormatArg(&tempString, &arguments[index - 1]);
FF_STRBUF_AUTO_DESTROY trailingEscape = ffStrbufCreate();
skipAnsiEscape(&tempString, buffer, &trailingEscape);
if (tempString.length == (uint32_t) truncLength) {
ffStrbufAppend(buffer, &tempString);
} else if (tempString.length > (uint32_t) truncLength) {
@@ -361,18 +730,46 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
} else if (cSep == ':') {
ffStrbufAppend(buffer, &tempString);
} else {
if (cSep == '<') {
if (cSep == '<') { // left align
ffStrbufAppend(buffer, &tempString);
ffStrbufAppendNC(buffer, (uint32_t) truncLength - tempString.length, ' ');
} else {
} else if (cSep == '>') { // right align
ffStrbufAppendNC(buffer, (uint32_t) truncLength - tempString.length, ' ');
ffStrbufAppend(buffer, &tempString);
} else if (cSep == '|') { // center align
uint32_t padding = ((uint32_t) truncLength - tempString.length) / 2;
ffStrbufAppendNC(buffer, padding, ' ');
ffStrbufAppend(buffer, &tempString);
ffStrbufAppendNC(buffer, (uint32_t) truncLength - tempString.length - padding, ' ');
}
}
if (trailingEscape.length > 0) {
ffStrbufAppend(buffer, &trailingEscape);
}
}
}
if (!instance.config.display.pipe) {
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
}
return true;
}
bool ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
#if FF_HAVE_QUICKJS
if (ffStrbufStartsWithS(formatstr, "qjs:")) {
return parseQuickJSString(buffer, formatstr->chars + 4, formatstr->length - 4, numArgs, arguments);
}
#endif
#if FF_HAVE_LUA
if (ffStrbufStartsWithS(formatstr, "lua:")) {
// If outputFormat starts with "lua:", treat the rest as a Lua script
return parseLuaString(buffer, formatstr->chars + 4, formatstr->length - 4, numArgs, arguments);
}
#endif
return parseFormatString(buffer, formatstr, numArgs, arguments);
}
File diff suppressed because it is too large Load Diff
+77 -44
View File
@@ -3,8 +3,8 @@
#include "common/parsing.h"
#include "common/thread.h"
#include "common/textModifier.h"
#include "common/strutil.h"
#include "detection/displayserver/displayserver.h"
#include "detection/terminaltheme/terminaltheme.h"
#include "logo/logo.h"
#include <stdlib.h>
@@ -16,6 +16,9 @@
#else
#include <signal.h>
#endif
#if __linux__
#include <linux/version.h>
#endif
FFinstance instance; // Global singleton
@@ -23,19 +26,10 @@ static void initState(FFstate* state) {
state->logoWidth = 0;
state->logoHeight = 0;
state->keysHeight = 0;
state->terminalLightTheme = false;
state->titleFqdn = false;
ffPlatformInit(&state->platform);
state->dynamicInterval = 0;
{
// don't enable bright color if the terminal is in light mode
FFTerminalThemeResult result;
if (ffDetectTerminalTheme(&result, true /* forceEnv for performance */) && !result.bg.dark) {
state->terminalLightTheme = true;
}
}
}
static void defaultConfig(void) {
@@ -44,10 +38,30 @@ static void defaultConfig(void) {
ffOptionsInitDisplay(&instance.config.display);
}
#ifdef _WIN32
static UINT oldCp = CP_UTF8;
void resetConsoleCP(void) {
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(oldCp);
}
}
#endif
void ffInitInstance(void) {
#ifdef _WIN32
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
setlocale(LC_ALL, ".UTF8");
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
if (GetConsoleMode(hStdout, &mode)) {
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
oldCp = GetConsoleOutputCP();
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(CP_UTF8);
atexit(resetConsoleCP);
}
}
#else
// Never use `setlocale(LC_ALL, "")`
setlocale(LC_TIME, "");
@@ -55,13 +69,14 @@ void ffInitInstance(void) {
defaultConfig();
initState(&instance.state);
#ifdef _WIN32
instance.state.platform.initCP = oldCp;
#endif
}
static volatile bool ffDisableLinewrap = true;
static volatile bool ffHideCursor = true;
#if _WIN32
static volatile UINT oldCp = CP_UTF8;
#endif
static volatile bool ffDisableLinewrap = false;
static volatile bool ffHideCursor = false;
static void resetConsole(void) {
if (ffDisableLinewrap) {
@@ -78,20 +93,16 @@ static void resetConsole(void) {
#if defined(_WIN32)
fflush(stdout);
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(oldCp);
}
#endif
}
#ifdef _WIN32
BOOL WINAPI consoleHandler(FF_A_UNUSED DWORD signal) {
BOOL WINAPI consoleHandler([[maybe_unused]] DWORD signal) {
resetConsole();
exit(0);
}
#else
static void exitSignalHandler(FF_A_UNUSED int signal) {
static void exitSignalHandler([[maybe_unused]] int signal) {
resetConsole();
exit(0);
}
@@ -104,32 +115,26 @@ void ffStart(void) {
#ifdef _WIN32
SetErrorMode(SEM_FAILCRITICALERRORS);
if (instance.config.display.noBuffer) {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdout, nullptr, _IONBF, 0);
} else {
setvbuf(stdout, NULL, _IOFBF, 4096);
setvbuf(stdout, nullptr, _IOFBF, 4096);
}
SetConsoleCtrlHandler(consoleHandler, TRUE);
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
if (GetConsoleMode(hStdout, &mode)) {
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
oldCp = GetConsoleOutputCP();
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(CP_UTF8);
}
}
#else
if (instance.config.display.noBuffer) {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdout, nullptr, _IONBF, 0);
}
struct sigaction action = { .sa_handler = exitSignalHandler };
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = exitSignalHandler;
sigaction(SIGINT, &action, nullptr);
sigaction(SIGTERM, &action, nullptr);
sigaction(SIGQUIT, &action, nullptr);
sigset_t newmask;
sigemptyset(&newmask);
sigaddset(&newmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &newmask, NULL);
sigprocmask(SIG_BLOCK, &newmask, nullptr);
#endif
// reset everything to default before we start printing
@@ -170,9 +175,19 @@ void ffDestroyInstance(void) {
destroyState();
}
#if FF_HAVE_LUA
#include <lua.h>
#endif
#if FF_HAVE_QUICKJS
#include <quickjs.h>
#endif
// Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
void ffListFeatures(void) {
fputs(
#if __linux__
"linux-headers " FF_STR(LINUX_VERSION_MAJOR) "." FF_STR(LINUX_VERSION_PATCHLEVEL) "." FF_STR(LINUX_VERSION_SUBLEVEL) "\n"
#endif
#if FF_HAVE_THREADS
"threads\n"
#endif
@@ -191,15 +206,15 @@ void ffListFeatures(void) {
#if FF_HAVE_DRM
"drm\n"
#endif
#if FF_HAVE_DRM_AMDGPU
"drm_amdgpu\n"
#endif
#if FF_HAVE_GIO
"gio\n"
#endif
#if FF_HAVE_DCONF
"dconf\n"
#endif
#if FF_HAVE_EET
"eet\n"
#endif
#if FF_HAVE_DBUS
"dbus\n"
#endif
@@ -245,23 +260,41 @@ void ffListFeatures(void) {
#if FF_HAVE_LIBZFS
"libzfs\n"
#endif
#if FF_HAVE_VADRM
"va-drm\n"
#endif
#if FF_HAVE_VAX11
"va-x11\n"
#endif
#if FF_HAVE_VDPAU
"vdpau\n"
#endif
#if FF_USE_SYSTEM_YYJSON
"System yyjson\n"
#endif
#if FF_HAVE_LINUX_VIDEODEV2
"linux/videodev2\n"
#endif
#if FF_HAVE_LINUX_WIRELESS
"linux/wireless\n"
#endif
#if FF_HAVE_EMBEDDED_PCIIDS
"Embedded pciids\n"
#endif
#if FF_ENABLE_WCWIDTH
"Embedded wcwidth\n"
#endif
#if FF_HAVE_WINRT
"WinRT headers\n"
#endif
#if FF_WIN81_COMPAT
"Windows 8.1 Compatibility\n"
#endif
#if FF_APPLE_MEMSIZE_USABLE
"Apple memsize_usable\n"
#endif
#if FF_HAVE_LUA
LUA_VERSION "\n"
#endif
#if FF_HAVE_QUICKJS
"QuickJS " FF_STR(QJS_VERSION_MAJOR) "." FF_STR(QJS_VERSION_MINOR) "." FF_STR(QJS_VERSION_PATCH) QJS_VERSION_SUFFIX "\n"
#endif
"",
stdout);
+15 -16
View File
@@ -1,6 +1,6 @@
#include "common/io.h"
#include "fastfetch.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "common/time.h"
#include <fcntl.h>
@@ -22,8 +22,8 @@
static void createSubfolders(const char* fileName) {
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* token = NULL;
while ((token = strchr(fileName, '/')) != NULL) {
const char* token = nullptr;
while ((token = strchr(fileName, '/')) != nullptr) {
ffStrbufAppendNS(&path, (uint32_t) (token - fileName + 1), fileName);
mkdir(path.chars, S_IRWXU | S_IRGRP | S_IROTH);
fileName = token + 1;
@@ -34,7 +34,7 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) {
int openFlagsModes = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
mode_t openFlagsRights = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int FF_AUTO_CLOSE_FD fd = open(fileName, openFlagsModes, openFlagsRights);
FF_AUTO_CLOSE_FD int fd = open(fileName, openFlagsModes, openFlagsRights);
if (fd == -1) {
if (errno == ENOENT) {
createSubfolders(fileName);
@@ -119,7 +119,7 @@ bool ffPathExpandEnv(const char* in, FFstrbuf* out) {
| GLOB_BRACE
#endif
,
NULL,
nullptr,
&gb) != 0)
return false;
@@ -174,7 +174,7 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
fd_set rd;
FD_ZERO(&rd);
FD_SET(ftty, &rd);
if (select(ftty + 1, &rd, NULL, NULL, &(struct timeval) { .tv_sec = FF_IO_TERM_RESP_WAIT_MS / 1000, .tv_usec = (FF_IO_TERM_RESP_WAIT_MS % 1000) * 1000 }) <= 0) {
if (select(ftty + 1, &rd, nullptr, nullptr, &(struct timeval) { .tv_sec = FF_IO_TERM_RESP_WAIT_MS / 1000, .tv_usec = (FF_IO_TERM_RESP_WAIT_MS % 1000) * 1000 }) <= 0) {
return "select(/dev/tty) timeout or failed";
}
}
@@ -213,7 +213,7 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
va_end(args);
return NULL;
return nullptr;
}
bool ffSuppressIO(bool suppress) {
@@ -252,19 +252,20 @@ bool ffSuppressIO(bool suppress) {
}
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty) {
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC);
int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC | O_DIRECTORY); // Ownership of dfd will be transformed to dir
if (dfd < 0) {
return;
}
DIR* dir = fdopendir(dfd);
if (dir == NULL) {
return;
FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd);
if (dir == nullptr) {
close(dfd);
return; // Should not happen
}
uint32_t folderLength = folder->length;
if (pretty && folderName != NULL) {
if (pretty && folderName != nullptr) {
for (uint8_t i = 0; i < indentation - 1; i++) {
fputs(" | ", stdout);
}
@@ -273,7 +274,7 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
while ((entry = readdir(dir)) != nullptr) {
if (entry->d_name[0] == '.') { // skip hidden files
continue;
}
@@ -310,14 +311,12 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
puts(entry->d_name);
}
closedir(dir);
}
void ffListFilesRecursively(const char* path, bool pretty) {
FF_STRBUF_AUTO_DESTROY folder = ffStrbufCreateS(path);
ffStrbufEnsureEndsWithC(&folder, '/');
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
listFilesRecursively(folder.length, &folder, 0, nullptr, pretty);
}
FFNativeFD ffGetNullFD(void) {
+38 -30
View File
@@ -1,6 +1,6 @@
#include "fastfetch.h"
#include "common/io.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "common/windows/nt.h"
#include "common/windows/unicode.h"
@@ -20,10 +20,10 @@ static bool createSubfolders(wchar_t* fileName) {
fileName,
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
nullptr,
OPEN_EXISTING,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
nullptr);
ptr[3] = saved;
if (hRoot == INVALID_HANDLE_VALUE) {
@@ -36,12 +36,12 @@ static bool createSubfolders(wchar_t* fileName) {
// UNC path: \\server\share\...
else if (ptr[0] == L'\\' && ptr[1] == L'\\') {
wchar_t* serverEnd = wcschr(ptr + 2, L'\\');
if (serverEnd == NULL) {
if (serverEnd == nullptr) {
return false;
}
wchar_t* shareEnd = wcschr(serverEnd + 1, L'\\');
if (shareEnd == NULL) {
if (shareEnd == nullptr) {
return true; // no parent subfolder exists before file name
}
@@ -52,10 +52,10 @@ static bool createSubfolders(wchar_t* fileName) {
fileName,
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
nullptr,
OPEN_EXISTING,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
nullptr);
*shareEnd = saved;
if (hRoot == INVALID_HANDLE_VALUE) {
@@ -73,10 +73,10 @@ static bool createSubfolders(wchar_t* fileName) {
driveRoot,
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
nullptr,
OPEN_EXISTING,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
NULL);
nullptr);
if (hRoot == INVALID_HANDLE_VALUE) {
return false;
}
@@ -86,7 +86,7 @@ static bool createSubfolders(wchar_t* fileName) {
while (true) {
wchar_t* token = wcschr(ptr, L'\\');
if (token == NULL) {
if (token == nullptr) {
break;
}
@@ -113,12 +113,12 @@ static bool createSubfolders(wchar_t* fileName) {
.Attributes = OBJ_CASE_INSENSITIVE,
},
&iosb,
NULL,
nullptr,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
nullptr,
0);
if (!NT_SUCCESS(status)) {
@@ -157,13 +157,13 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) {
}
}
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
FF_AUTO_CLOSE_FD HANDLE handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (handle == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_PATH_NOT_FOUND) {
if (!createSubfolders(fileNameW)) {
return false;
}
handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (handle == INVALID_HANDLE_VALUE) {
return false;
}
@@ -173,15 +173,15 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) {
}
DWORD written;
return !!WriteFile(handle, data, (DWORD) dataSize, &written, NULL);
return !!WriteFile(handle, data, (DWORD) dataSize, &written, nullptr);
}
static inline void readWithLength(HANDLE handle, FFstrbuf* buffer, uint32_t length) {
ffStrbufEnsureFree(buffer, length);
ffStrbufEnsureFixedLengthFree(buffer, length);
DWORD bytesRead = 0;
while (
length > 0 &&
ReadFile(handle, buffer->chars + buffer->length, length, &bytesRead, NULL) != FALSE &&
ReadFile(handle, buffer->chars + buffer->length, length, &bytesRead, nullptr) != FALSE &&
bytesRead > 0) {
buffer->length += (uint32_t) bytesRead;
length -= (uint32_t) bytesRead;
@@ -193,7 +193,7 @@ static inline void readUntilEOF(HANDLE handle, FFstrbuf* buffer) {
uint32_t available = ffStrbufGetFree(buffer);
DWORD bytesRead = 0;
while (
ReadFile(handle, buffer->chars + buffer->length, available, &bytesRead, NULL) != FALSE &&
ReadFile(handle, buffer->chars + buffer->length, available, &bytesRead, nullptr) != FALSE &&
bytesRead > 0) {
buffer->length += (uint32_t) bytesRead;
if ((uint32_t) bytesRead == available) {
@@ -282,7 +282,7 @@ bool ffPathExpandEnv(const char* in, FFstrbuf* out) {
len /= sizeof(wchar_t); // convert from bytes to characters
SIZE_T outLen; // in characters, including null terminator
if (!NT_SUCCESS(RtlExpandEnvironmentStrings(NULL, pathInW, len, pathOutW, ARRAY_SIZE(pathOutW), &outLen))) {
if (!NT_SUCCESS(RtlExpandEnvironmentStrings(nullptr, pathInW, len, pathOutW, ARRAY_SIZE(pathOutW), &outLen))) {
return false;
}
@@ -336,7 +336,7 @@ bool ffSuppressIO(bool suppress) {
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty) {
uint32_t folderLength = folder->length;
if (pretty && folderName != NULL) {
if (pretty && folderName != nullptr) {
for (uint8_t i = 0; i < indentation - 1; i++) {
fputs(" | ", stdout);
}
@@ -381,16 +381,18 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
void ffListFilesRecursively(const char* path, bool pretty) {
FF_STRBUF_AUTO_DESTROY folder = ffStrbufCreateS(path);
ffStrbufEnsureEndsWithC(&folder, '/');
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
listFilesRecursively(folder.length, &folder, 0, nullptr, pretty);
}
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...) {
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
FF_AUTO_CLOSE_FD HANDLE hConin = INVALID_HANDLE_VALUE;
DWORD inputMode;
if (!GetConsoleMode(hInput, &inputMode)) {
hConin = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
DWORD inputMode = 0;
bool hasInputMode = !!GetConsoleMode(hInput, &inputMode);
if (!hasInputMode) {
hConin = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, nullptr);
hInput = hConin;
hasInputMode = !!GetConsoleMode(hInput, &inputMode);
}
SetConsoleMode(hInput, 0);
@@ -402,10 +404,10 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
FF_AUTO_CLOSE_FD HANDLE hConout = INVALID_HANDLE_VALUE;
DWORD outputMode;
if (!GetConsoleMode(hOutput, &outputMode)) {
hConout = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
hConout = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, nullptr);
hOutput = hConout;
}
WriteFile(hOutput, request, (DWORD) strlen(request), &bytes, NULL);
WriteFile(hOutput, request, (DWORD) strlen(request), &bytes, nullptr);
}
while (true) {
@@ -439,12 +441,16 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
while (true) {
DWORD bytes = 0;
if (!ReadFile(hInput, buffer, sizeof(buffer) - 1, &bytes, NULL) || bytes == 0) {
if (!ReadFile(hInput, buffer + bytesRead, (DWORD) (sizeof(buffer) - 1 - bytesRead), &bytes, nullptr) || bytes == 0) {
va_end(args);
return "ReadFile() failed";
}
bytesRead += bytes;
if (__builtin_expect(bytesRead >= sizeof(buffer) - 1, false)) {
va_end(args);
return "terminal response buffer overflow";
}
buffer[bytesRead] = '\0';
va_list cargs;
@@ -461,11 +467,13 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
}
}
SetConsoleMode(hInput, inputMode);
if (hasInputMode) {
SetConsoleMode(hInput, inputMode);
}
va_end(args);
return NULL;
return nullptr;
}
FFNativeFD ffGetNullFD(void) {
@@ -482,7 +490,7 @@ FFNativeFD ffGetNullFD(void) {
0,
&(SECURITY_ATTRIBUTES) {
.nLength = sizeof(SECURITY_ATTRIBUTES),
.lpSecurityDescriptor = NULL,
.lpSecurityDescriptor = nullptr,
.bInheritHandle = TRUE,
});
return hNullFile;
+52 -28
View File
@@ -4,7 +4,7 @@
#include "common/printing.h"
#include "common/io.h"
#include "common/time.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include "detection/version/version.h"
#include "modules/modules.h"
@@ -67,7 +67,7 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair) {
if (intVal == pPair->value) {
*result = pPair->value;
return NULL;
return nullptr;
}
}
@@ -77,7 +77,7 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair) {
if (ffStrEqualsIgnCase(strVal, pPair->key)) {
*result = pPair->value;
return NULL;
return nullptr;
}
}
@@ -95,7 +95,7 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(type[0]) - 'A']; *modules; ++modules) {
FFModuleBaseInfo* baseInfo = *modules;
if (ffStrEqualsIgnCase(type, baseInfo->name)) {
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
alignas(uint64_t) uint8_t optionBuf[FF_OPTION_MAX_SIZE];
baseInfo->initOptions(optionBuf);
if (jsonVal) {
baseInfo->parseJsonObject(optionBuf, jsonVal);
@@ -133,17 +133,13 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
switch (type[0]) {
case 'b':
case 'B': {
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME)) {
ffPrepareCPUUsage();
}
break;
}
#if !FF_MODULE_DISABLE_CPUUSAGE
case 'c':
case 'C': {
if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME)) {
FF_A_CLEANUP(ffDestroyCommandOptions) FFCommandOptions options;
if (ffStrEqualsIgnCase(type, ffCPUUsageModuleInfo.name)) {
ffPrepareCPUUsage();
} else if (ffStrEqualsIgnCase(type, ffCommandModuleInfo.name)) {
[[gnu::cleanup(ffDestroyCommandOptions)]] FFCommandOptions options;
ffInitCommandOptions(&options);
if (module) {
ffCommandModuleInfo.parseJsonObject(&options, module);
@@ -152,10 +148,13 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
}
break;
}
#endif
#if !FF_MODULE_DISABLE_DISKIO
case 'd':
case 'D': {
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME)) {
FF_A_CLEANUP(ffDestroyDiskIOOptions) FFDiskIOOptions options;
if (ffStrEqualsIgnCase(type, ffDiskIOModuleInfo.name)) {
[[gnu::cleanup(ffDestroyDiskIOOptions)]] FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
if (module) {
ffDiskIOModuleInfo.parseJsonObject(&options, module);
@@ -164,10 +163,13 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
}
break;
}
#endif
#if !FF_MODULE_DISABLE_NETIO
case 'n':
case 'N': {
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME)) {
FF_A_CLEANUP(ffDestroyNetIOOptions) FFNetIOOptions options;
if (ffStrEqualsIgnCase(type, ffNetIOModuleInfo.name)) {
[[gnu::cleanup(ffDestroyNetIOOptions)]] FFNetIOOptions options;
ffInitNetIOOptions(&options);
if (module) {
ffNetIOModuleInfo.parseJsonObject(&options, module);
@@ -176,10 +178,13 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
}
break;
}
#endif
#if !FF_MODULE_DISABLE_PUBLICIP
case 'p':
case 'P': {
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME)) {
FF_A_CLEANUP(ffDestroyPublicIpOptions) FFPublicIPOptions options;
if (ffStrEqualsIgnCase(type, ffPublicIPModuleInfo.name)) {
[[gnu::cleanup(ffDestroyPublicIpOptions)]] FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
if (module) {
ffPublicIPModuleInfo.parseJsonObject(&options, module);
@@ -188,10 +193,28 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
}
break;
}
#endif
#if !FF_MODULE_DISABLE_TOP
case 't':
case 'T': {
if (ffStrEqualsIgnCase(type, ffTopModuleInfo.name)) {
[[gnu::cleanup(ffDestroyTopOptions)]] FFTopOptions options;
ffInitTopOptions(&options);
if (module) {
ffTopModuleInfo.parseJsonObject(&options, module);
}
ffPrepareTopProcesses(options.showTypes);
}
break;
}
#endif
#if !FF_MODULE_DISABLE_WEATHER
case 'w':
case 'W': {
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME)) {
FF_A_CLEANUP(ffDestroyWeatherOptions) FFWeatherOptions options;
if (ffStrEqualsIgnCase(type, ffWeatherModuleInfo.name)) {
[[gnu::cleanup(ffDestroyWeatherOptions)]] FFWeatherOptions options;
ffInitWeatherOptions(&options);
if (module) {
ffWeatherModuleInfo.parseJsonObject(&options, module);
@@ -200,6 +223,7 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
}
break;
}
#endif
}
}
@@ -235,7 +259,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) {
yyjson_val* modules = yyjson_obj_get(root, "modules");
if (!modules) {
return NULL;
return nullptr;
}
if (!yyjson_is_arr(modules)) {
return "Property 'modules' must be an array of strings or objects";
@@ -254,12 +278,12 @@ static const char* printJsonConfig(FFdata* data, bool prepare) {
yyjson_val* module = item;
const char* type = yyjson_get_str(module);
if (type) {
module = NULL;
module = nullptr;
} else if (yyjson_is_obj(module)) {
yyjson_val* conditions = yyjson_obj_get(module, "condition");
if (conditions) {
if (!yyjson_is_obj(conditions)) {
return "Property 'conditions' must be an object";
return "Property 'condition' must be an object";
}
yyjson_val* system = yyjson_obj_get(conditions, "system");
@@ -298,7 +322,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) {
return "module object must contain a \"type\" key ( case sensitive )";
}
if (yyjson_obj_size(module) == 1) { // contains only Property type
module = NULL;
module = nullptr;
}
} else {
return "modules must be an array of strings or objects";
@@ -327,7 +351,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) {
: FF_COLOR_FG_RED),
ms);
}
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len - 1, str); // Save; Up 1; Right 9999999; Left <len - 1>; Print <str>; Load
}
}
@@ -338,7 +362,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) {
#endif
}
return NULL;
return nullptr;
}
void ffPrintJsonConfig(FFdata* data, bool prepare) {
@@ -350,7 +374,7 @@ void ffPrintJsonConfig(FFdata* data, bool prepare) {
yyjson_mut_obj_add_str(jsonDoc, obj, "error", error);
yyjson_mut_doc_set_root(jsonDoc, obj);
} else {
ffPrintError("JsonConfig", 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "%s", error);
ffPrintError("JsonConfig", 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "%s", error);
}
}
}

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