Compare commits

...

170 Commits

Author SHA1 Message Date
dependabot[bot] 37ec63d1bd 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-23 18:07:14 +00: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
663 changed files with 9348 additions and 4965 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
[codespell]
check-filenames =
builtin = clear,rare,usage,informal
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./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_*
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu,renderD,SME,Carmel,kinda
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
+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:
- "*"
+6 -3
View File
@@ -3,6 +3,9 @@ name: Reusable DragonFly amd64
on:
workflow_call:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -12,10 +15,10 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@master
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: dragonflybsd
version: '6.4.2'
@@ -57,7 +60,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-dragonfly-amd64
path: ./fastfetch-*.*
+7 -4
View File
@@ -3,6 +3,9 @@ name: Reusable FreeBSD amd64
on:
workflow_call:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -12,10 +15,10 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@master
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: freebsd
version: '15.1'
@@ -31,7 +34,7 @@ jobs:
- 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-tcl egl opencl ocl-icd v4l_compat chafa lua54 libva libvdpau
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' }} .
@@ -58,7 +61,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-freebsd-amd64
path: ./fastfetch-*.*
+6 -3
View File
@@ -3,6 +3,9 @@ name: Reusable Haiku amd64
on:
workflow_call:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -12,10 +15,10 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@master
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: haiku
version: 'r1beta5'
@@ -51,7 +54,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-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@v7
- 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 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 -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-*.*
+6 -3
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@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: uraimo/run-on-arch-action@v3
uses: uraimo/run-on-arch-action@f9b26e3a1a408d5fd530d20c17b9f3f4428ff8d9 # v3.1.0
id: runcmd
with:
arch: armv7
@@ -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-*.*
+8 -4
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@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: uname -a
run: uname -a
@@ -48,7 +52,7 @@ jobs:
- name: Initialize CodeQL
if: inputs.arch == 'amd64'
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
with:
languages: c
@@ -60,7 +64,7 @@ jobs:
- name: perform CodeQL analysis
if: inputs.arch == 'amd64'
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4.37.7
- name: list features
run: ./fastfetch --list-features
@@ -97,7 +101,7 @@ 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-*.*
+5 -2
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@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: uname -a
run: uname -a
@@ -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-*.*
+6 -3
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@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: run VM
uses: uraimo/run-on-arch-action@v3
uses: uraimo/run-on-arch-action@f9b26e3a1a408d5fd530d20c17b9f3f4428ff8d9 # v3.1.0
id: runcmd
with:
arch: ${{ inputs.arch }}
@@ -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-*.*
+5 -2
View File
@@ -10,6 +10,9 @@ on:
required: true
type: string
permissions:
contents: read
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
@@ -18,7 +21,7 @@ jobs:
runs-on: ${{ inputs.runs-on }}
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: uname -a
run: uname -a
@@ -53,7 +56,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-macos-${{ inputs.arch }}
path: ./fastfetch-*.*
+6 -3
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,10 +13,10 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- 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
@@ -41,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-*.*
+6 -3
View File
@@ -3,6 +3,9 @@ name: Reusable NetBSD amd64
on:
workflow_call:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -12,10 +15,10 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@master
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: netbsd
version: '10.1'
@@ -56,7 +59,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-netbsd-amd64
path: ./fastfetch-*.*
+4 -1
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,7 +15,7 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: uname -a
run: uname -a
+6 -3
View File
@@ -3,6 +3,9 @@ name: Reusable OmniOS amd64
on:
workflow_call:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -12,10 +15,10 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@master
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: omnios
version: 'r151058'
@@ -61,7 +64,7 @@ jobs:
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-*.*
+6 -3
View File
@@ -3,6 +3,9 @@ name: Reusable OpenBSD amd64
on:
workflow_call:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
@@ -12,10 +15,10 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Start VM
uses: cross-platform-actions/action@master
uses: cross-platform-actions/action@24ef01df165c76df1ed2b9f9e9212e78dc2fc963 # v1.4.0
with:
operating_system: openbsd
version: '7.9'
@@ -56,7 +59,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-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 }}
+6 -3
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,10 +14,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: checkout repository
uses: actions/checkout@v7
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'
@@ -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-*.*
+4 -1
View File
@@ -3,13 +3,16 @@ name: Reusable Spellcheck
on:
workflow_call:
permissions:
contents: read
jobs:
spellcheck:
runs-on: ubuntu-latest
steps:
- name: checkout repository
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install codespell
shell: bash
+17 -5
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,10 +42,10 @@ jobs:
shell: msys2 {0}
steps:
- name: checkout repository
uses: actions/checkout@v7
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
@@ -72,7 +84,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 +94,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,7 +111,7 @@ 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 }}.*
+19 -34
View File
@@ -6,16 +6,16 @@ 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
@@ -34,40 +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:
linux-loong64:
needs: no-features-test
name: Linux-armv6l
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:
@@ -78,19 +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:
@@ -103,71 +94,65 @@ 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:
if: false # Disabled because the Haiku build is currently broken
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:
@@ -188,7 +173,8 @@ jobs:
msystem: ${{ matrix.msystem }}
msystem-lower: ${{ matrix.msystem-lower }}
msys-arch: ${{ matrix.msys-arch }}
secrets: inherit
secrets:
SIGNPATH_API_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN }}
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
@@ -197,7 +183,7 @@ jobs:
- linux-hosts
- linux-i686
- linux-armv7l
- linux-armv6l
- linux-loong64
- linux-vms
- musl-amd64
- macos-hosts
@@ -207,11 +193,10 @@ jobs:
- dragonfly-amd64
- solaris-amd64
- omnios-amd64
- haiku-amd64
# - haiku-amd64
- windows-hosts
permissions:
contents: write
uses: ./.github/workflows/build-release.yml
with:
ffversion: ${{ needs.linux-hosts.outputs.ffversion }}
secrets: inherit
+1
View File
@@ -12,3 +12,4 @@ fastfetch.kdev4
*.user
*.user.*
*.swp
*.log
+91 -5
View File
@@ -1,3 +1,89 @@
# Unreleased
Changes:
* The DE / WM / LM modules now reports the full name "Desktop Environment" / "Window Manager" / "Login Manager" instead of the abbreviations.
Features:
* 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.
* 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)
Bugfixes:
* Fixed I/O rate calculation precision in DiskIO and NetIO, and prevented division by zero. (DiskIO / NetIO)
* Some internal cleanups and optimizations.
# 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:
@@ -6,9 +92,9 @@ Changes:
Bugfixes:
* Fixed compatibility with WSL 2.9.3 (#2433, WM, Linux)
* Fixed accurate AMD GPU names are not queried in `driverSpecific` mode (GPU, 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
* Some internal cleanups and optimizations.
Features:
* Added Astra Linux version detection (OS, Linux)
@@ -741,7 +827,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)
@@ -1252,7 +1338,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)
@@ -1720,7 +1806,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
+59 -14
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
cmake_minimum_required(VERSION 3.21.0) # C_STANDARD
project(fastfetch
VERSION 2.66.0
VERSION 2.67.1
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -62,6 +62,7 @@ if(NOT PKG_CONFIG_FOUND)
endif()
include(CheckIncludeFile)
include(CheckFunctionExists)
if(LINUX)
CHECK_INCLUDE_FILE("linux/version.h" HAVE_LINUX_VERSION_H)
@@ -182,7 +183,30 @@ endif()
set(WARNING_FLAGS "-Wall -Wextra -Wconversion -Werror=uninitialized -Werror=return-type -Werror=vla")
set(CMAKE_C_STANDARD 11)
if(LINUX)
if(NOT IS_MUSL) # `NOT DEFINED IS_MUSL` doesn't work
execute_process(
COMMAND ${CMAKE_C_COMPILER} -print-file-name=libc.so
OUTPUT_VARIABLE LIBC_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(LIBC_PATH MATCHES "-musl")
set(IS_MUSL ON CACHE BOOL "Build with musl libc" FORCE)
endif()
endif()
if(IS_MUSL)
message(STATUS "MUSL libc detected")
# Silence ioctl related warnings
set(WARNING_FLAGS "${WARNING_FLAGS} -Wno-sign-conversion")
endif()
endif()
# Minimal compiler version supported: GCC 13 (2023-04-26), Clang 16 (2023-03-17)
# Most C23 features are allowed with noticeable exceptions of `constexpr` and `#embed`
# See https://cppreference.com/c/compiler_support/23 for detail
set(CMAKE_C_STANDARD 23)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=incompatible-pointer-types -Werror=implicit-function-declaration -Werror=int-conversion")
if(WIN32 OR Haiku)
@@ -411,6 +435,7 @@ set(LIBFASTFETCH_SRC
src/common/impl/font.c
src/common/impl/format.c
src/common/impl/frequency.c
src/common/impl/genconfig.c
src/common/impl/init.c
src/common/impl/jsonconfig.c
src/common/impl/library.c
@@ -998,7 +1023,7 @@ elseif(APPLE)
src/detection/cpu/cpu_apple.c
src/detection/cpucache/cpucache_apple.c
src/detection/cpuusage/cpuusage_apple.c
src/detection/cursor/cursor_apple.m
src/detection/cursor/cursor_apple.c
src/detection/disk/disk_bsd.c
src/detection/dns/dns_apple.c
src/detection/physicaldisk/physicaldisk_apple.c
@@ -1039,7 +1064,7 @@ elseif(APPLE)
src/detection/wifi/wifi_apple.m
src/detection/wm/wm_apple.m
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_apple.m
src/detection/wmtheme/wmtheme_apple.c
src/detection/camera/camera_apple.m
)
# CMAKE_SYSTEM_PROCESSOR has been normalized before
@@ -1100,7 +1125,7 @@ elseif(WIN32)
src/detection/gpu/gpu_windows.cpp
src/detection/host/host_windows.c
src/detection/icons/icons_windows.c
src/detection/initsystem/initsystem_nosupport.c
src/detection/initsystem/initsystem_windows.c
src/detection/keyboard/keyboard_windows.c
src/detection/libc/libc_windows.cpp
src/detection/lm/lm_nosupport.c
@@ -1144,7 +1169,7 @@ elseif(SunOS)
src/common/impl/FFPlatform_unix.c
src/common/impl/binary_linux.c
src/common/impl/kmod_sunos.c
src/detection/battery/battery_nosupport.c
src/detection/battery/battery_sunos.c
src/detection/bios/bios_windows.c
src/detection/board/board_windows.c
src/detection/bootmgr/bootmgr_nosupport.c
@@ -1210,7 +1235,7 @@ elseif(SunOS)
src/detection/uptime/uptime_sunos.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_linux.c
src/detection/wifi/wifi_nosupport.c
src/detection/wifi/wifi_sunos.c
src/detection/wm/wm_nosupport.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
@@ -1257,7 +1282,6 @@ elseif(Haiku)
src/detection/keyboard/keyboard_haiku.cpp
src/detection/libc/libc_nosupport.c
src/detection/lm/lm_nosupport.c
src/detection/loadavg/loadavg_nosupport.c
src/detection/locale/locale_linux.c
src/detection/localip/localip_linux.c
src/detection/gamepad/gamepad_haiku.cpp
@@ -1281,12 +1305,19 @@ elseif(Haiku)
src/detection/uptime/uptime_haiku.c
src/detection/users/users_linux.c
src/detection/wallpaper/wallpaper_haiku.cpp
src/detection/wifi/wifi_nosupport.c
src/detection/wifi/wifi_haiku.cpp
src/detection/wm/wm_nosupport.c
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_haiku.cpp
src/detection/camera/camera_nosupport.c
)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} bsd)
check_function_exists(getloadavg HAVE_GETLOADAVG)
if(HAVE_GETLOADAVG)
list(APPEND LIBFASTFETCH_SRC src/detection/loadavg/loadavg_sunos.c)
else()
list(APPEND LIBFASTFETCH_SRC src/detection/loadavg/loadavg_nosupport.c)
endif()
elseif(GNU)
list(APPEND LIBFASTFETCH_SRC
src/common/impl/dbus.c
@@ -1404,7 +1435,6 @@ if(WIN32)
endif()
endif()
endif()
include(CheckFunctionExists)
if(NOT WIN32)
check_function_exists(pipe2 HAVE_PIPE2)
endif()
@@ -1445,10 +1475,24 @@ endforeach()
include(CheckCSourceCompiles)
check_c_source_compiles("int main(void){int arr[1];return _Countof(arr);}" COMPILER_SUPPORTS_COUNT_OF)
if(COMPILER_SUPPORTS_COUNT_OF)
message(STATUS "_Countof is supported by the compiler")
message(STATUS "C2Y _Countof is supported by the compiler")
target_compile_definitions(libfastfetch PUBLIC FF_SUPPORTS_COUNT_OF=1)
else()
message(STATUS "_Countof is NOT supported by the compiler")
message(STATUS "C2Y _Countof is NOT supported by the compiler")
endif()
# Test C23 compiler support
check_c_source_compiles("enum my_enum: long{MY_ENUM_ZERO}; void test(void*p){} int main(int,const char**){[[gnu::cleanup(test)]] void* x=nullptr; return (int)MY_ENUM_ZERO;}" COMPILER_SUPPORTS_C23)
if(NOT COMPILER_SUPPORTS_C23)
message(FATAL_ERROR "Compiler does not support C23. Please use a newer compiler.")
endif()
# A hack for AppleClang 17, which supports most C23 features we use except for the `auto` keyword.
# See https://github.com/Homebrew/homebrew-core/pull/297403
check_c_source_compiles("int main(void){auto v = 12.34; return (int)v;}" COMPILER_SUPPORTS_AUTO)
if(NOT COMPILER_SUPPORTS_AUTO)
message(WARNING "Compiler does not support C23 'auto' keyword. A workaround will be applied.")
target_compile_definitions(libfastfetch PUBLIC $<$<COMPILE_LANGUAGE:C>:auto=__auto_type>)
endif()
if(yyjson_FOUND)
@@ -1531,7 +1575,7 @@ elseif(Haiku)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE)
elseif(GNU)
# On Hurd PATH_MAX is not defined. Set an arbitrary limit as workaround.
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=0)
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE PATH_MAX=4096 O_PATH=O_NORW)
endif()
if(APPLE)
@@ -1982,6 +2026,7 @@ elseif(Haiku)
PRIVATE "GL"
PRIVATE "be"
PRIVATE "gnu"
PRIVATE "bsd"
)
endif()
+7 -6
View File
@@ -99,7 +99,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 +199,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 +335,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__":
+12
View File
@@ -1,3 +1,15 @@
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
+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",
+115 -10
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",
@@ -912,11 +912,6 @@
"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",
@@ -1062,6 +1057,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"
}
}
},
@@ -2590,8 +2695,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": {
@@ -3491,8 +3596,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": {
+7
View File
@@ -16,6 +16,13 @@
"separator",
"os",
"host",
{
"type": "board",
"key": "Host",
"condition": {
"succeeded": false
}
},
{
"type": "kernel",
"format": "{release}"
+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);
+31 -13
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
@@ -23,33 +22,33 @@ 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;
@@ -59,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;
}
@@ -87,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) {
@@ -112,12 +111,25 @@ static inline void* ffListAdd(FFlist* list, uint32_t elementSize) {
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) \
({ \
@@ -127,6 +139,12 @@ static inline void* ffListAdd(FFlist* list, uint32_t elementSize) {
#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) \
({ \
@@ -136,9 +154,9 @@ static inline void* ffListAdd(FFlist* list, uint32_t elementSize) {
#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); \
})
+73 -79
View File
@@ -1,7 +1,5 @@
#pragma once
#include "common/attributes.h"
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
@@ -10,6 +8,7 @@
#include <stdlib.h>
#include <assert.h>
#include "common/memrchr.h"
#include "common/arrutil.h"
#ifdef FF_USE_SYSTEM_YYJSON
#include <yyjson.h>
@@ -37,15 +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);
FF_A_PRINTF(2, 3) void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...);
FF_A_PRINTF(1, 2) FF_A_NODISCARD FFstrbuf ffStrbufCreateF(const char* format, ...);
[[gnu::format(printf, 2, 3)]] void ffStrbufInitF(FFstrbuf* strbuf, const char* format, ...);
[[gnu::format(printf, 1, 2)]] [[nodiscard]] FFstrbuf ffStrbufCreateF(const char* format, ...);
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free);
void ffStrbufEnsureFreeNoCheck(FFstrbuf* strbuf, uint32_t free);
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict 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);
@@ -58,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);
@@ -79,7 +78,7 @@ 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);
@@ -90,7 +89,7 @@ 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);
@@ -103,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.
@@ -135,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;
@@ -150,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;
@@ -166,7 +165,7 @@ 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;
@@ -185,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;
}
@@ -210,7 +209,7 @@ static inline void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free) {
static inline void ffStrbufClear(FFstrbuf* strbuf) {
assert(strbuf != NULL);
assert(strbuf != nullptr);
extern char* CHAR_NULL_PTR;
if (strbuf->allocated == 0) {
@@ -223,9 +222,7 @@ static inline void ffStrbufClear(FFstrbuf* strbuf) {
}
static inline void ffStrbufAppendC(FFstrbuf* strbuf, char c) {
if (__builtin_expect(ffStrbufGetFree(strbuf) == 0, false)) {
ffStrbufEnsureFreeNoCheck(strbuf, 1);
}
ffStrbufEnsureFree(strbuf, 1);
strbuf->chars[strbuf->length++] = c;
strbuf->chars[strbuf->length] = '\0';
}
@@ -234,9 +231,7 @@ static inline void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c) {
if (__builtin_expect(num == 0, false)) {
return;
}
if (__builtin_expect(ffStrbufGetFree(strbuf) < num, false)) {
ffStrbufEnsureFreeNoCheck(strbuf, num);
}
ffStrbufEnsureFree(strbuf, num);
memset(&strbuf->chars[strbuf->length], c, num);
strbuf->length += num;
@@ -244,12 +239,10 @@ static inline void ffStrbufAppendNC(FFstrbuf* strbuf, uint32_t num, char c) {
}
static inline void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value) {
if (__builtin_expect(value == NULL || length == 0, false)) {
if (__builtin_expect(value == nullptr || length == 0, false)) {
return;
}
if (__builtin_expect(ffStrbufGetFree(strbuf) < length, false)) {
ffStrbufEnsureFreeNoCheck(strbuf, length);
}
ffStrbufEnsureFree(strbuf, length);
memcpy(&strbuf->chars[strbuf->length], value, length);
strbuf->length += length;
@@ -258,7 +251,7 @@ static inline void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const cha
static inline void ffStrbufAppend(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict value) {
assert(value != strbuf);
if (value == NULL) {
if (value == nullptr) {
return;
}
ffStrbufAppendNS(strbuf, value->length, value->chars);
@@ -269,9 +262,9 @@ static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf) {
}
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);
@@ -279,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));
@@ -291,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);
@@ -311,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;
@@ -328,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;
@@ -339,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);
@@ -351,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;
@@ -367,113 +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 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);
}
FF_A_NODISCARD static inline uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, 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;
}
FF_A_NODISCARD static inline uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) {
[[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;
}
FF_A_NODISCARD static inline uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
[[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;
}
static inline FF_A_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) {
[[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;
}
@@ -489,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;
}
@@ -501,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;
}
@@ -536,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);
}
@@ -614,19 +607,19 @@ static inline void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file) {
fputc('\n', file);
}
FF_A_NODISCARD static inline double ffStrbufToDouble(const FFstrbuf* strbuf, double defaultValue) {
[[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;
}
FF_A_NODISCARD static inline uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue) {
[[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;
}
FF_A_NODISCARD static inline int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue) {
[[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;
@@ -635,4 +628,5 @@ FF_A_NODISCARD static inline int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int6
// 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 }
+25 -25
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,13 +22,13 @@ 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(*result)) {
return "Data length is not sizeof(int32_t)";
}
CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(*result)), (uint8_t*) result);
return NULL;
return nullptr;
}
return "TypeID is neither 'CFNumber' nor 'CFData'";
@@ -40,7 +40,7 @@ const char* ffCfNumGetDouble(CFTypeRef cf, double* result) {
!CFNumberGetValue((CFNumberRef) cf, kCFNumberFloatType, result)) {
return "Number type is not Double or Float";
}
return NULL;
return nullptr;
}
return "TypeID is neither 'CFNumber'";
@@ -54,13 +54,13 @@ const char* ffCfDateGetEpoch(CFTypeRef cf, uint64_t* result) {
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 NULL;
return nullptr;
}
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) {
ffStrbufClear(result);
if (!cf) {
return NULL;
return nullptr;
}
if (CFGetTypeID(cf) == CFStringGetTypeID()) {
@@ -72,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)) {
@@ -86,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);
@@ -96,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);
@@ -119,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";
}
@@ -133,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";
}
@@ -142,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";
}
@@ -151,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";
}
@@ -165,7 +165,7 @@ 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";
}
@@ -174,7 +174,7 @@ const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* res
const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* result) {
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
if (cf == NULL) {
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
@@ -183,7 +183,7 @@ const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* res
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";
}
@@ -202,22 +202,22 @@ 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 == NULL) {
if (cf == nullptr) {
return "CFDictionaryGetValue() failed";
}
+3 -3
View File
@@ -4,7 +4,7 @@
#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);
@@ -32,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);
@@ -40,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)]]
+45 -10
View File
@@ -86,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
@@ -103,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) {
@@ -130,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) {
@@ -143,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) {
@@ -270,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) {
@@ -291,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;
}
}
@@ -303,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;
}
}
@@ -392,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;
@@ -442,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
@@ -452,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;
}
@@ -461,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,
+1 -1
View File
@@ -16,7 +16,7 @@ bool ffGetAppNameAndVersion(const char* exePath, FFstrbuf* retName, FFstrbuf* re
lastSlash -= strlen("MacOS");
char infoPlistPath[PATH_MAX];
memcpy(infoPlistPath, exePath, lastSlash - exePath);
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)]
+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,
+2 -2
View File
@@ -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
-20
View File
@@ -1,20 +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__))
#define FF_A_ALWAYS_INLINE __attribute__((__always_inline__))
#define FF_A_COLD __attribute__((__cold__))
+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"
+3 -3
View File
@@ -26,7 +26,7 @@ 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, uint64_t* result);
@@ -38,9 +38,9 @@ bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* ob
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
+2 -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;
+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);
}
+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);
+1
View File
@@ -18,6 +18,7 @@ void ffPlatformInit(FFPlatform* platform) {
#ifdef _WIN32
ffStrbufInit(&platform->sid);
platform->initCP = 0;
#endif
FFPlatformSysinfo* info = &platform->sysinfo;
+6 -6
View File
@@ -57,7 +57,7 @@ static void getExePath(FFPlatform* platform) {
4,
exePath,
&exePathLen,
NULL,
nullptr,
0) < 0)
exePathLen = 0;
else {
@@ -68,7 +68,7 @@ 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);
kvm_t* kd = kvm_openfiles(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
if (kd) {
int kpCount;
struct kinfo_proc* kp = kvm_getprocs(kd, KERN_PROC_PID, (pid_t) platform->pid, sizeof(*kp), &kpCount);
@@ -77,7 +77,7 @@ static void getExePath(FFPlatform* platform) {
if (argv && argv[0]) {
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)) {
@@ -88,7 +88,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;
}
@@ -282,7 +282,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
@@ -290,7 +290,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, '/');
}
+18 -18
View File
@@ -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,8 +142,8 @@ 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); // Required. userName.Buffer is allocated separately
LsaFreeMemory(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;
+50 -29
View File
@@ -1,6 +1,7 @@
#include "common/FFstrbuf.h"
#include "common/mallocHelper.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);
@@ -64,13 +65,25 @@ FFstrbuf ffStrbufCreateF(const char* format, ...) {
}
void ffStrbufEnsureFreeNoCheck(FFstrbuf* strbuf, uint32_t free) {
uint32_t allocate = strbuf->length + 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();
}
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();
}
// 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.
assert(allocate < (UINT32_MAX >> 1));
// allocate = __builtin_stdc_bit_ceil(allocate + 1); // Currently generates worse asm code
allocate = 1U << (32 - __builtin_clz(allocate));
}
@@ -91,16 +104,17 @@ void ffStrbufEnsureFreeNoCheck(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';
@@ -109,6 +123,15 @@ 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);
}
@@ -116,7 +139,7 @@ void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free) {
}
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int (*transformFunc)(int)) {
if (value == NULL) {
if (value == nullptr) {
return;
}
@@ -134,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);
@@ -155,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);
@@ -169,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);
@@ -186,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);
@@ -195,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;
}
@@ -213,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));
@@ -410,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;
}
@@ -533,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);
}
@@ -546,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);
}
@@ -713,7 +734,7 @@ bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const
for (const char* p = comp; p < comp + compLength;) {
const char* colon = memchr(p, separator, (size_t) (comp + compLength - p));
if (colon == NULL) {
if (colon == nullptr) {
uint32_t remainingLen = (uint32_t) (comp + compLength - p);
return strbuf->length == remainingLen && memcmp(strbuf->chars, p, remainingLen) == 0;
}
@@ -741,7 +762,7 @@ bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength
for (const char* p = comp; p < comp + compLength;) {
const char* colon = memchr(p, separator, (size_t) (comp + compLength - p));
if (colon == NULL) {
if (colon == nullptr) {
uint32_t remainingLen = (uint32_t) (comp + compLength - p);
return strbuf->length == remainingLen && strncasecmp(strbuf->chars, p, remainingLen) == 0;
}
+7 -1
View File
@@ -6,7 +6,13 @@ 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;
#if !__BIG_ENDIAN__
// The 3 input bytes must be laid out big-endian (str[0] in the most
// significant position). On little-endian hosts swap; on big-endian
// hosts the word is already in the right order.
n = __builtin_bswap32(n);
#endif
*out++ = chars[(n >> 26) & 63];
*out++ = chars[(n >> 20) & 63];
*out++ = chars[(n >> 14) & 63];
+11 -11
View File
@@ -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;
@@ -99,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;
@@ -124,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) {
@@ -153,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) {
@@ -174,13 +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 nullptr;
}
/**
@@ -195,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);
@@ -273,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) {
+13 -13
View File
@@ -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;
}
@@ -131,7 +131,7 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
}
elfData.ffelf_end(elf);
return NULL;
return nullptr;
}
#else
+6 -6
View File
@@ -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";
}
@@ -67,5 +67,5 @@ const char* ffBinaryExtractStrings(const char* peFile, bool (*cb)(const char* st
}
NtUnmapViewOfSection(NtCurrentProcess(), base);
return NULL;
return nullptr;
}
+18 -23
View File
@@ -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,16 +64,16 @@ 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
@@ -81,8 +81,8 @@ void ffPrepareCommandOption(FFdata* data) {
#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);
}
@@ -92,8 +92,8 @@ void ffPrepareCommandOption(FFdata* data) {
#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);
}
@@ -103,8 +103,8 @@ void ffPrepareCommandOption(FFdata* data) {
#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);
}
@@ -114,8 +114,8 @@ void ffPrepareCommandOption(FFdata* data) {
#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);
}
@@ -175,9 +175,9 @@ static bool 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 (data->resultDoc != NULL) {
if (data->resultDoc != nullptr) {
fn(data, baseInfo, optionBuf);
} else {
baseInfo->printModule(optionBuf);
@@ -194,7 +194,7 @@ static bool parseStructureCommand(
yyjson_mut_obj_add_str(doc, module, "type", line);
yyjson_mut_obj_add_str(doc, module, "error", "Unknown module type");
} else {
ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
ffPrintError(line, 0, nullptr, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
}
return false;
}
@@ -203,7 +203,7 @@ 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, ':')) {
@@ -244,12 +244,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, ':')) {
+17 -17
View File
@@ -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)) {
@@ -254,8 +254,8 @@ bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int64_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) {
@@ -266,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);
@@ -275,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,
@@ -286,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);
@@ -295,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;
}
@@ -314,7 +314,7 @@ bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char*
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;
}
+2 -2
View File
@@ -10,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);
+7 -7
View File
@@ -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;
@@ -488,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;
}
+33 -19
View File
@@ -78,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;
@@ -109,10 +109,24 @@ 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 && *(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 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
}
FF_A_UNUSED static inline void normalizeArgName(FFstrbuf* dst, const char* src) {
[[maybe_unused]] static inline void normalizeArgName(FFstrbuf* dst, const char* src) {
ffStrbufClear(dst);
bool flag = false;
for (const char* p = src; *p; ++p) {
@@ -131,7 +145,7 @@ FF_A_UNUSED static inline void normalizeArgName(FFstrbuf* dst, const char* src)
#include "common/lua.h"
static void appendLuaError(FFstrbuf* buffer, const char* prefix, lua_State* L) {
const char* err = lua_tolstring(L, -1, NULL);
const char* err = lua_tolstring(L, -1, nullptr);
if (err) {
const char* tmp = strchr(err, ':');
if (tmp) {
@@ -228,12 +242,12 @@ static bool parseLuaString(FFstrbuf* buffer, const char* script, uint32_t script
ffStrbufAppendS(buffer, "Lua result error: no result");
} else {
// Convert first result to string
const char* res = lua_tolstring(L, 1, NULL);
const char* res = lua_tolstring(L, 1, nullptr);
if (res) {
ffStrbufAppendS(buffer, res);
} else {
luaL_tolstring(L, 1, NULL);
const char* sval = lua_tolstring(L, -1, NULL);
luaL_tolstring(L, 1, nullptr);
const char* sval = lua_tolstring(L, -1, nullptr);
if (sval) {
ffStrbufAppendS(buffer, sval);
}
@@ -273,10 +287,10 @@ struct FFQuickJSData {
static const char* loadQuickJSState(void) {
if (qjsData.inited) {
if (qjsData.ctx == NULL) {
if (qjsData.ctx == nullptr) {
return "QuickJS is not available";
}
return NULL;
return nullptr;
}
qjsData.inited = true;
@@ -301,20 +315,20 @@ static const char* loadQuickJSState(void) {
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_FreeValue)
qjsData.rt = qjsData.ffJS_NewRuntime();
if (qjsData.rt == NULL) {
if (qjsData.rt == nullptr) {
return "JS_NewRuntime() failed";
}
qjsData.ctx = qjsData.ffJS_NewContext(qjsData.rt);
if (qjsData.ctx == NULL) {
if (qjsData.ctx == nullptr) {
qjsData.ffJS_FreeRuntime(qjsData.rt);
qjsData.rt = NULL;
qjsData.rt = nullptr;
return "JS_NewContext() failed";
}
libqjs = NULL; // don't close quickjs
libqjs = nullptr; // don't close quickjs
return NULL;
return nullptr;
}
static bool parseQuickJSString(FFstrbuf* buffer, const char* script, uint32_t scriptLen, uint32_t numArgs, const FFformatarg* arguments) {
@@ -401,7 +415,7 @@ static bool parseQuickJSString(FFstrbuf* buffer, const char* script, uint32_t sc
bool ret = false;
if (JS_IsException(result)) {
JSValue exc = qjsData.ffJS_GetException(ctx);
const char* message = qjsData.ffJS_ToCStringLen2(ctx, NULL, exc, false);
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) {
@@ -587,7 +601,7 @@ static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint3
// 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
@@ -620,7 +634,7 @@ static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint3
cSep = *pSep;
*pSep = '\0';
} else {
pSep = NULL;
pSep = nullptr;
}
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
@@ -646,7 +660,7 @@ static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint3
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;
@@ -680,7 +694,7 @@ static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint3
continue;
}
} else {
char* pEnd = NULL;
char* pEnd = nullptr;
int32_t truncLength = (int32_t) strtol(pSep + 1, &pEnd, 10);
if (*pEnd != '\0') {
*pSep = cSep;
File diff suppressed because it is too large Load Diff
+14 -22
View File
@@ -5,7 +5,6 @@
#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>
@@ -27,21 +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;
#if !FF_MODULE_DISABLE_TERMINALTHEME
{
// 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;
}
}
#endif
}
static void defaultConfig(void) {
@@ -51,7 +39,7 @@ static void defaultConfig(void) {
}
#ifdef _WIN32
static volatile UINT oldCp = CP_UTF8;
static UINT oldCp = CP_UTF8;
void resetConsoleCP(void) {
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(oldCp);
@@ -81,6 +69,10 @@ void ffInitInstance(void) {
defaultConfig();
initState(&instance.state);
#ifdef _WIN32
instance.state.platform.initCP = oldCp;
#endif
}
static volatile bool ffDisableLinewrap = false;
@@ -105,12 +97,12 @@ static void resetConsole(void) {
}
#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);
}
@@ -123,26 +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);
#else
if (instance.config.display.noBuffer) {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdout, nullptr, _IONBF, 0);
}
struct sigaction action;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_handler = exitSignalHandler;
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
sigaction(SIGQUIT, &action, NULL);
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
+10 -10
View File
@@ -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) {
@@ -258,14 +258,14 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
}
FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd);
if (dir == NULL) {
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);
}
@@ -274,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;
}
@@ -316,7 +316,7 @@ 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);
}
FFNativeFD ffGetNullFD(void) {
+25 -25
View File
@@ -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,7 +173,7 @@ 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) {
@@ -181,7 +181,7 @@ static inline void readWithLength(HANDLE handle, FFstrbuf* buffer, uint32_t leng
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,7 +381,7 @@ 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, ...) {
@@ -390,7 +390,7 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
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, NULL);
hConin = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, nullptr);
hInput = hConin;
hasInputMode = !!GetConsoleMode(hInput, &inputMode);
}
@@ -404,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) {
@@ -441,7 +441,7 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
while (true) {
DWORD bytes = 0;
if (!ReadFile(hInput, buffer + bytesRead, (DWORD) (sizeof(buffer) - 1 - bytesRead), &bytes, NULL) || bytes == 0) {
if (!ReadFile(hInput, buffer + bytesRead, (DWORD) (sizeof(buffer) - 1 - bytesRead), &bytes, nullptr) || bytes == 0) {
va_end(args);
return "ReadFile() failed";
}
@@ -473,7 +473,7 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
va_end(args);
return NULL;
return nullptr;
}
FFNativeFD ffGetNullFD(void) {
@@ -490,7 +490,7 @@ FFNativeFD ffGetNullFD(void) {
0,
&(SECURITY_ATTRIBUTES) {
.nLength = sizeof(SECURITY_ATTRIBUTES),
.lpSecurityDescriptor = NULL,
.lpSecurityDescriptor = nullptr,
.bInheritHandle = TRUE,
});
return hNullFile;
+19 -19
View File
@@ -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);
@@ -136,10 +136,10 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#if !FF_MODULE_DISABLE_CPUUSAGE
case 'c':
case 'C': {
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME)) {
if (ffStrEqualsIgnCase(type, ffCPUUsageModuleInfo.name)) {
ffPrepareCPUUsage();
} else if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME)) {
FF_A_CLEANUP(ffDestroyCommandOptions) FFCommandOptions options;
} else if (ffStrEqualsIgnCase(type, ffCommandModuleInfo.name)) {
[[gnu::cleanup(ffDestroyCommandOptions)]] FFCommandOptions options;
ffInitCommandOptions(&options);
if (module) {
ffCommandModuleInfo.parseJsonObject(&options, module);
@@ -153,8 +153,8 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#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);
@@ -168,8 +168,8 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#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);
@@ -183,8 +183,8 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#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);
@@ -198,8 +198,8 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
#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);
@@ -244,7 +244,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";
@@ -263,7 +263,7 @@ 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) {
@@ -307,7 +307,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";
@@ -347,7 +347,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) {
#endif
}
return NULL;
return nullptr;
}
void ffPrintJsonConfig(FFdata* data, bool prepare) {
@@ -359,7 +359,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);
}
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
bool ffKmodLoaded(const char* modName) {
FF_CFTYPE_AUTO_RELEASE CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, modName, kCFStringEncodingUTF8);
FF_CFTYPE_AUTO_RELEASE CFArrayRef identifiers = CFArrayCreate(kCFAllocatorDefault, (const void**) &name, 1, &kCFTypeArrayCallBacks);
FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL);
FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, nullptr, 0, nullptr);
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef kextInfo = KextManagerCopyLoadedKextInfo(identifiers, keys);
return CFDictionaryContainsKey(kextInfo, name);
}
+2 -2
View File
@@ -3,7 +3,7 @@
bool ffKmodLoaded(const char* modName) {
static FFstrbuf modules;
if (modules.chars == NULL) {
if (modules.chars == nullptr) {
ffStrbufInitS(&modules, "\n");
ffAppendFileBuffer("/proc/modules", &modules);
}
@@ -21,5 +21,5 @@ bool ffKmodLoaded(const char* modName) {
temp[0] = '\n';
memcpy(temp + 1, modName, len);
temp[1 + len] = ' ';
return memmem(modules.chars, modules.length, temp, len + 2) != NULL;
return memmem(modules.chars, modules.length, temp, len + 2) != nullptr;
}
+3 -3
View File
@@ -4,15 +4,15 @@
#include <sys/module.h>
#include <sys/param.h>
typedef struct FF_A_PACKED FFNbsdModList {
typedef struct [[gnu::packed]] FFNbsdModList {
int len;
modstat_t mods[];
} FFNbsdModList;
bool ffKmodLoaded(const char* modName) {
static FFNbsdModList* list = NULL;
static FFNbsdModList* list = nullptr;
if (list == NULL) {
if (list == nullptr) {
struct iovec iov = {};
for (size_t len = 8192;; len = iov.iov_len) {
+1 -1
View File
@@ -1,5 +1,5 @@
#include "common/kmod.h"
bool ffKmodLoaded(FF_A_UNUSED const char* modName) {
bool ffKmodLoaded([[maybe_unused]] const char* modName) {
return true; // Don't generate kernel module related errors
}
+1 -1
View File
@@ -5,7 +5,7 @@
bool ffKmodLoaded(const char* modName) {
ULONG bufferSize = 0;
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &bufferSize);
NtQuerySystemInformation(SystemModuleInformation, nullptr, 0, &bufferSize);
if (bufferSize == 0) {
return true; // ignore errors
}
+95 -15
View File
@@ -35,7 +35,7 @@ void* ffLibraryLoadSingle(const char* path, int maxVersion) {
// libX.dll.1 never exists on Windows, while libX-1.dll may exist
FF_UNUSED(maxVersion)
if (result != NULL) {
if (result != nullptr) {
return result;
}
@@ -50,11 +50,11 @@ void* ffLibraryLoadSingle(const char* path, int maxVersion) {
#else
if (result == NULL) {
if (result == nullptr) {
FF_DEBUG("dlopen(\"%s\"): %s", path, dlerror());
}
if (result != NULL || maxVersion < 0) {
if (result != nullptr || maxVersion < 0) {
return result;
}
@@ -67,7 +67,7 @@ void* ffLibraryLoadSingle(const char* path, int maxVersion) {
ffStrbufAppendSInt(&pathbuf, i);
result = dlopen(pathbuf.chars, FF_DLOPEN_FLAGS);
if (result != NULL) {
if (result != nullptr) {
break;
} else {
FF_DEBUG("dlopen(\"%s\"): %s", pathbuf.chars, dlerror());
@@ -90,7 +90,7 @@ void* ffLibraryLoadMulti(const char* path, int maxVersion, ...) {
do {
const char* pathRest = va_arg(defaultNames, const char*);
if (pathRest == NULL) {
if (pathRest == nullptr) {
break;
}
@@ -108,18 +108,18 @@ void* ffLibraryLoadMulti(const char* path, int maxVersion, ...) {
#if _WIN32
void* dlopen(const char* path, FF_A_UNUSED int mode) {
void* dlopen(const char* path, [[maybe_unused]] int mode) {
wchar_t pathW[MAX_PATH + 1];
ULONG pathWBytes = 0;
NTSTATUS status = RtlUTF8ToUnicodeN(pathW, sizeof(pathW), &pathWBytes, path, (uint32_t) strlen(path) + 1);
if (!NT_SUCCESS(status)) {
FF_DEBUG("RtlUTF8ToUnicodeN failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
return NULL;
return nullptr;
}
PVOID module = NULL;
status = LdrLoadDll(NULL, NULL, &(UNICODE_STRING) {
PVOID module = nullptr;
status = LdrLoadDll(nullptr, nullptr, &(UNICODE_STRING) {
.Length = (USHORT) (pathWBytes - sizeof(wchar_t)), // Exclude null terminator
.MaximumLength = (USHORT) pathWBytes,
.Buffer = pathW,
@@ -128,7 +128,7 @@ void* dlopen(const char* path, FF_A_UNUSED int mode) {
if (!NT_SUCCESS(status)) {
FF_DEBUG("LdrLoadDll failed for path %s with status 0x%08lX: %s", path, status, ffDebugNtStatus(status));
return NULL;
return nullptr;
}
return module;
@@ -155,17 +155,17 @@ void* dlsym(void* handle, const char* symbol) {
&address);
if (!NT_SUCCESS(status)) {
FF_DEBUG("LdrGetProcedureAddress failed for symbol %s with status 0x%08lX: %s", symbol, status, ffDebugNtStatus(status));
return NULL;
return nullptr;
}
return address;
}
void* ffLibraryGetModule(const wchar_t* libraryFileName) {
assert(libraryFileName != NULL && "Use \"ffGetPeb()->ImageBaseAddress\" instead");
assert(libraryFileName != nullptr && "Use \"ffGetPeb()->ImageBaseAddress\" instead");
void* module = NULL;
void* module = nullptr;
USHORT libraryFileNameBytes = (USHORT) (wcslen(libraryFileName) * sizeof(wchar_t) + sizeof(wchar_t));
NTSTATUS status = LdrGetDllHandle(NULL, NULL, &(UNICODE_STRING) {
NTSTATUS status = LdrGetDllHandle(nullptr, nullptr, &(UNICODE_STRING) {
.Length = libraryFileNameBytes - sizeof(wchar_t),
.MaximumLength = libraryFileNameBytes,
.Buffer = (wchar_t*) libraryFileName,
@@ -173,8 +173,88 @@ void* ffLibraryGetModule(const wchar_t* libraryFileName) {
&module);
if (!NT_SUCCESS(status)) {
FF_DEBUG("LdrGetDllHandle failed for library %ls with status 0x%08lX: %s", libraryFileName, status, ffDebugNtStatus(status));
return NULL;
return nullptr;
}
return module;
}
#endif
struct LibraryIterateDynamicLibsBundle {
FFLibraryIterateCallback callback;
void* userData;
};
#if _WIN32
static void ffLibraryIterateDynamicLibsCallback(PLDR_DATA_TABLE_ENTRY DataTableEntry, PVOID Context, BOOLEAN* StopEnumeration) {
if (DataTableEntry->FullDllName.Buffer == nullptr || DataTableEntry->FullDllName.Buffer[0] == L'\0') {
return;
}
char path[PATH_MAX * 3];
ULONG outBytes;
if (NT_SUCCESS(RtlUnicodeToUTF8N(path, sizeof(path), &outBytes, DataTableEntry->FullDllName.Buffer, DataTableEntry->FullDllName.Length))) {
path[outBytes] = '\0';
struct LibraryIterateDynamicLibsBundle* bundle = (struct LibraryIterateDynamicLibsBundle*) Context;
*StopEnumeration = !bundle->callback(path, bundle->userData);
}
}
bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) {
struct LibraryIterateDynamicLibsBundle bundle = {
.callback = callback,
.userData = userData,
};
return NT_SUCCESS(LdrEnumerateLoadedModules(FALSE, ffLibraryIterateDynamicLibsCallback, &bundle));
}
#elif defined(__APPLE__)
#include <mach-o/dyld.h>
bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback callback, void* userData) {
uint32_t imageCount = _dyld_image_count();
for (uint32_t i = 0; i < imageCount; ++i) {
const char* name = _dyld_get_image_name(i);
if (name == nullptr || name[0] == '\0') {
continue;
}
if (!callback(name, userData)) {
break;
}
}
return true;
}
#elif __has_include(<link.h>)
#include <link.h>
static int ffLibraryIterateDynamicLibsCallback(struct dl_phdr_info* info, size_t, void* data) {
if (info->dlpi_name == nullptr || info->dlpi_name[0] == '\0') {
return 0;
}
struct LibraryIterateDynamicLibsBundle* bundle = (struct LibraryIterateDynamicLibsBundle*) data;
return !bundle->callback(info->dlpi_name, bundle->userData);
}
bool ffLibraryIterateDynamicLibs(bool (*callback)(const char* name, void* userData), void* userData) {
dl_iterate_phdr(
ffLibraryIterateDynamicLibsCallback,
&(struct LibraryIterateDynamicLibsBundle) {
.callback = callback,
.userData = userData,
});
return true;
}
#else
bool ffLibraryIterateDynamicLibs(FFLibraryIterateCallback, void*) {
// Not implemented for this platform
return false;
}
#endif
+8 -8
View File
@@ -109,7 +109,7 @@ static int yyjsonEncode(lua_State* L) {
pretty = (int) lua_toboolean(L, 2);
}
yyjson_mut_doc* doc = yyjson_mut_doc_new(NULL);
yyjson_mut_doc* doc = yyjson_mut_doc_new(nullptr);
if (__builtin_expect(!doc, false)) {
lua_pushlstring(L, "yyjson: yyjson_mut_doc_new() failed", strlen("yyjson: yyjson_mut_doc_new() failed"));
return lua_error(L);
@@ -120,9 +120,9 @@ static int yyjsonEncode(lua_State* L) {
size_t jsonLen;
yyjson_write_err err = {};
FF_AUTO_FREE const char* jsonStr = yyjson_mut_write_opts(doc, YYJSON_WRITE_ALLOW_INF_AND_NAN | (pretty ? YYJSON_WRITE_PRETTY_TWO_SPACES : 0), NULL, &jsonLen, &err);
FF_AUTO_FREE const char* jsonStr = yyjson_mut_write_opts(doc, YYJSON_WRITE_ALLOW_INF_AND_NAN | (pretty ? YYJSON_WRITE_PRETTY_TWO_SPACES : 0), nullptr, &jsonLen, &err);
if (__builtin_expect(jsonStr != NULL, true)) {
if (__builtin_expect(jsonStr != nullptr, true)) {
lua_pushlstring(L, jsonStr, jsonLen);
yyjson_mut_doc_free(doc);
return 1;
@@ -140,10 +140,10 @@ static int yyjsonEncode(lua_State* L) {
const char* ffLuaLoadState(void) {
if (luaData.inited) {
if (luaData.L == NULL) {
if (luaData.L == nullptr) {
return "Lua library is not available";
}
return NULL;
return nullptr;
}
luaData.inited = true;
@@ -211,7 +211,7 @@ const char* ffLuaLoadState(void) {
#endif
lua_State* L = ffluaL_newstate();
if (L == NULL) {
if (L == nullptr) {
return "luaL_newstate() failed";
}
#if LUA_VERSION_NUM >= 505
@@ -226,8 +226,8 @@ const char* ffLuaLoadState(void) {
lua_pushcfunction(L, yyjsonEncode);
lua_setglobal(L, "json_encode");
luaData.L = L;
liblua = NULL; // don't close lua
return NULL;
liblua = nullptr; // don't close lua
return nullptr;
}
#endif
+2 -2
View File
@@ -4,7 +4,7 @@
void* memrchr(const void* s, int c, size_t n) {
if (n == 0) {
return NULL;
return nullptr;
}
const uint8_t uc = (uint8_t) c;
@@ -17,5 +17,5 @@ void* memrchr(const void* s, int c, size_t n) {
}
}
return NULL;
return nullptr;
}
+1 -1
View File
@@ -52,7 +52,7 @@ get_rt_address(struct rt_msghdr* rtm, int desired) {
sa = (struct sockaddr*) (ROUNDUP(salen) + (char*) sa);
}
}
return NULL;
return nullptr;
}
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
+5 -5
View File
@@ -39,20 +39,20 @@ get_rt_address(struct rt_msghdr* rtm, int desired) {
sa = (struct sockaddr*) (ROUNDUP(sa->sa_len) + (char*) sa);
}
}
return NULL;
return nullptr;
}
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_GATEWAY };
size_t needed;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0) {
if (sysctl(mib, 6, nullptr, &needed, nullptr, 0) < 0 || needed == 0) {
return false;
}
FF_AUTO_FREE char* buf = malloc(needed);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
if (sysctl(mib, 6, buf, &needed, nullptr, 0) < 0) {
return false;
}
@@ -89,13 +89,13 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY };
size_t needed;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0) {
if (sysctl(mib, 6, nullptr, &needed, nullptr, 0) < 0 || needed == 0) {
return false;
}
FF_AUTO_FREE char* buf = malloc(needed);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
if (sysctl(mib, 6, buf, &needed, nullptr, 0) < 0) {
return false;
}
+1 -1
View File
@@ -6,7 +6,7 @@
#include <stdio.h>
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/route", "r");
FF_AUTO_CLOSE_FILE FILE* netRoute = fopen("/proc/route", "r");
if (!netRoute) {
return false;
+8 -8
View File
@@ -29,7 +29,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
}
FF_AUTO_FREE void* buffer = malloc((size_t) size);
if (buffer == NULL) {
if (buffer == nullptr) {
return false;
}
@@ -54,13 +54,13 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
}
size_t addressSize = 0;
if (interface->ifr_route.destination != NULL) {
if (interface->ifr_route.destination != nullptr) {
addressSize += interface->ifr_route.destination->sa_len;
}
if (interface->ifr_route.mask != NULL) {
if (interface->ifr_route.mask != nullptr) {
addressSize += interface->ifr_route.mask->sa_len;
}
if (interface->ifr_route.gateway != NULL) {
if (interface->ifr_route.gateway != nullptr) {
addressSize += interface->ifr_route.gateway->sa_len;
}
@@ -88,7 +88,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
}
FF_AUTO_FREE void* buffer = malloc((size_t) size);
if (buffer == NULL) {
if (buffer == nullptr) {
return false;
}
@@ -109,13 +109,13 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
}
size_t addressSize = 0;
if (interface->ifr_route.destination != NULL) {
if (interface->ifr_route.destination != nullptr) {
addressSize += interface->ifr_route.destination->sa_len;
}
if (interface->ifr_route.mask != NULL) {
if (interface->ifr_route.mask != nullptr) {
addressSize += interface->ifr_route.mask->sa_len;
}
if (interface->ifr_route.gateway != NULL) {
if (interface->ifr_route.gateway != nullptr) {
addressSize += interface->ifr_route.gateway->sa_len;
}
+8 -8
View File
@@ -44,7 +44,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
uint32_t pid = ffNetifGetNetlinkPortId(sock_fd);
struct FF_A_PACKED {
struct [[gnu::packed]] {
struct nlmsghdr nlh;
struct rtmsg rtm;
struct rtattr rta;
@@ -97,7 +97,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
uint32_t minMetric = UINT32_MAX;
FF_A_UNUSED int routeCount = 0;
[[maybe_unused]] int routeCount = 0;
while (true) {
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0, (struct sockaddr*) &src_addr, &src_addr_len);
@@ -163,7 +163,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
}
FF_DEBUG("Processing IPv4 default route candidate #%d", routeCount);
entry = (__typeof__(entry)) {}; // Default to zero metric (no RTA_PRIORITY found)
entry = (typeof(entry)) {}; // Default to zero metric (no RTA_PRIORITY found)
// Parse route attributes
size_t rtm_len = RTM_PAYLOAD(nlh);
@@ -254,7 +254,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
uint32_t pid = ffNetifGetNetlinkPortId(sock_fd);
struct FF_A_PACKED {
struct [[gnu::packed]] {
struct nlmsghdr nlh;
struct rtmsg rtm;
struct rtattr rta;
@@ -307,7 +307,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
uint32_t minMetric = UINT32_MAX;
FF_A_UNUSED int routeCount = 0;
[[maybe_unused]] int routeCount = 0;
while (true) {
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0, (struct sockaddr*) &src_addr, &src_addr_len);
@@ -372,7 +372,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
}
FF_DEBUG("Processing IPv6 default route candidate #%d", routeCount);
entry = (__typeof__(entry)) {}; // Default to zero metric (no RTA_PRIORITY found)
entry = (typeof(entry)) {}; // Default to zero metric (no RTA_PRIORITY found)
// Parse route attributes
size_t rtm_len = RTM_PAYLOAD(nlh);
@@ -382,7 +382,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
switch (rta->rta_type) {
case RTA_DST:
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
FF_A_UNUSED char str[INET6_ADDRSTRLEN];
[[maybe_unused]] char str[INET6_ADDRSTRLEN];
FF_DEBUG("Unexpected RTA_DST: %s", inet_ntop(AF_INET6, RTA_DATA(rta), str, sizeof(str)));
goto next;
}
@@ -399,7 +399,7 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
if (IN6_IS_ADDR_UNSPECIFIED(gw)) {
goto next;
}
FF_A_UNUSED char str[INET6_ADDRSTRLEN];
[[maybe_unused]] char str[INET6_ADDRSTRLEN];
FF_DEBUG("Found gateway: %s", inet_ntop(AF_INET6, gw, str, sizeof(str)));
}
break;
+2 -2
View File
@@ -4,7 +4,7 @@
#include <iphlpapi.h>
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
PMIB_IPFORWARD_TABLE2 pIpForwardTable = nullptr;
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_INET, &pIpForwardTable))) {
return false;
@@ -48,7 +48,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
}
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
PMIB_IPFORWARD_TABLE2 pIpForwardTable = nullptr;
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_INET6, &pIpForwardTable))) {
return false;
+5 -5
View File
@@ -29,9 +29,9 @@ const char* ffNetworkingLoadZlibLibrary(void) {
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateInit2_)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflate)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(zlib, zlibData, inflateEnd)
zlib = NULL; // don't auto dlclose
zlib = nullptr; // don't auto dlclose
}
return zlibData.ffinflateEnd == NULL ? "Failed to load libz" : NULL;
return zlibData.ffinflateEnd == nullptr ? "Failed to load libz" : nullptr;
}
// Try to pre-read gzip header to determine uncompressed size
@@ -64,14 +64,14 @@ static uint32_t guessGzipOutputSize(const void* data, uint32_t dataSize) {
// Decompress gzip content
bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd) {
assert(headerEnd != NULL && *headerEnd == '\r');
assert(headerEnd != nullptr && *headerEnd == '\r');
// Calculate header size
uint32_t headerSize = (uint32_t) (headerEnd - buffer->chars);
*headerEnd = '\0'; // Replace delimiter with null character for easier processing
// Ensure Content-Encoding is in response headers, not in response body
bool hasGzip = strcasestr(buffer->chars, "\nContent-Encoding: gzip") != NULL;
bool hasGzip = strcasestr(buffer->chars, "\nContent-Encoding: gzip") != nullptr;
*headerEnd = '\r'; // Restore delimiter
if (!hasGzip) {
@@ -165,7 +165,7 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd) {
// Use decompressedBuffer.length (total) not decompressedSize (last chunk only)
FF_STRBUF_AUTO_DESTROY newBuffer = ffStrbufCreateA(headerSize + decompressedBuffer.length + 64);
char* line = NULL;
char* line = nullptr;
size_t len = 0;
while (ffStrbufGetline(&line, &len, buffer)) {
if (ffStrStartsWithIgnCase(line, "Content-Encoding:")) {
+27 -20
View File
@@ -97,7 +97,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state) {
},
1,
&sent,
NULL) != 0) {
nullptr) != 0) {
sent = 0;
}
if (fcntl(state->sockfd, F_SETFL, 0) == -1) {
@@ -123,9 +123,9 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state) {
sent,
strerror(errno));
freeaddrinfo(state->addr);
state->addr = NULL;
state->addr = nullptr;
ffStrbufDestroy(&state->command);
return NULL;
return nullptr;
}
FF_DEBUG(
@@ -149,7 +149,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state) {
// Traditional connect and send function
static const char* connectAndSend(FFNetworkingState* state) {
const char* ret = NULL;
const char* ret = nullptr;
FF_DEBUG("Using traditional connection method to connect");
FF_DEBUG("Attempting connect() to server...");
@@ -178,7 +178,7 @@ error:
exit:
FF_DEBUG("Releasing address info and other resources");
freeaddrinfo(state->addr);
state->addr = NULL;
state->addr = nullptr;
ffStrbufDestroy(&state->command);
return ret;
@@ -212,7 +212,7 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
FF_DEBUG("Thread ID initialized to 0");
#endif
const char* ret = NULL;
const char* ret = nullptr;
struct addrinfo hints = {
.ai_family = state->ipv6 ? AF_INET6 : AF_INET,
@@ -261,7 +261,7 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
if (state->timeout > 0) {
FF_DEBUG("Setting connection timeout: %u ms", state->timeout);
FF_A_UNUSED uint32_t sec = state->timeout / 1000;
[[maybe_unused]] uint32_t sec = state->timeout / 1000;
if (sec == 0) {
sec = 1;
}
@@ -280,14 +280,14 @@ static const char* initNetworkingState(FFNetworkingState* state, const char* hos
#endif
}
return NULL;
return nullptr;
error:
FF_DEBUG("Error occurred during initialization");
if (state->addr != NULL) {
if (state->addr != nullptr) {
FF_DEBUG("Releasing address information");
freeaddrinfo(state->addr);
state->addr = NULL;
state->addr = nullptr;
}
if (state->sockfd > 0) {
@@ -307,7 +307,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
#ifdef FF_HAVE_ZLIB
const char* zlibError = ffNetworkingLoadZlibLibrary();
// Only enable compression if zlib library is successfully loaded
if (zlibError == NULL) {
if (zlibError == nullptr) {
FF_DEBUG("Successfully loaded zlib library, compression enabled");
} else {
FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError);
@@ -322,16 +322,16 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
}
const char* initResult = initNetworkingState(state, host, path, headers);
if (initResult != NULL) {
if (initResult != nullptr) {
FF_DEBUG("Initialization failed: %s", initResult);
return initResult;
}
FF_DEBUG("Network state initialization successful");
const char* tfoResult = tryNonThreadingFastPath(state);
if (tfoResult == NULL) {
if (tfoResult == nullptr) {
FF_DEBUG("TryNonThreadingFastPath() succeeded or in progress");
return NULL;
return nullptr;
}
FF_DEBUG("TryNonThreadingFastPath() failed: %s, trying traditional connection", tfoResult);
@@ -341,7 +341,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
if (state->thread) {
FF_DEBUG("Thread creation successful: thread=%p", (void*) (uintptr_t) state->thread);
return NULL;
return nullptr;
}
FF_DEBUG("Thread creation failed");
} else {
@@ -406,7 +406,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
FF_DEBUG("Setting receive timeout: %u ms", timeout);
struct timeval timev;
timev.tv_sec = timeout / 1000;
timev.tv_usec = (__typeof__(timev.tv_usec)) ((timeout % 1000) * 1000); // milliseconds to microseconds
timev.tv_usec = (typeof(timev.tv_usec)) ((timeout % 1000) * 1000); // milliseconds to microseconds
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev));
}
#endif
@@ -417,7 +417,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
}
FF_DEBUG("Starting data reception");
FF_A_UNUSED int recvCount = 0;
[[maybe_unused]] int recvCount = 0;
uint32_t contentLength = 0;
uint32_t headerEnd = 0;
@@ -455,8 +455,15 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
// Check for Content-Length header to pre-allocate enough memory
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
if (clHeader) {
contentLength = (uint32_t) strtoul(clHeader + 15, NULL, 10);
contentLength = (uint32_t) strtoul(clHeader + 15, nullptr, 10);
if (contentLength > 0) {
if (contentLength > 1024 * 1024) { // 1MB limit to prevent excessive memory allocation and potential attacks
FF_DEBUG("Content-Length is too large: %u bytes, aborting", contentLength);
close(state->sockfd);
state->sockfd = -1;
return "Content-Length too large";
}
FF_DEBUG("Detected Content-Length: %u, pre-allocating buffer", contentLength);
// Ensure buffer is large enough, adding header size and some margin
ffStrbufEnsureFree(buffer, contentLength + 16);
@@ -481,7 +488,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
return "No HTTP header end found";
}
if (!ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
if (!ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n") && !ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n")) {
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
return "Invalid response";
}
@@ -505,5 +512,5 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
}
#endif
return NULL;
return nullptr;
}
+44 -49
View File
@@ -23,7 +23,7 @@ static const char* initWsaData(WSADATA* wsaData) {
}
// Dummy socket needed for WSAIoctl
SOCKET sockfd = WSASocketW(AF_INET, SOCK_STREAM, 0, NULL, 0, 0);
SOCKET sockfd = WSASocketW(AF_INET, SOCK_STREAM, 0, nullptr, 0, 0);
if (sockfd == INVALID_SOCKET) {
FF_DEBUG("WSASocketW(AF_INET, SOCK_STREAM) failed");
WSACleanup();
@@ -32,7 +32,7 @@ static const char* initWsaData(WSADATA* wsaData) {
DWORD dwBytes;
GUID guid = WSAID_CONNECTEX;
if (WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx), &dwBytes, NULL, NULL) != 0) {
if (WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &ConnectEx, sizeof(ConnectEx), &dwBytes, nullptr, nullptr) != 0) {
FF_DEBUG("WSAIoctl(sockfd, SIO_GET_EXTENSION_FUNCTION_POINTER) failed");
closesocket(sockfd);
WSACleanup();
@@ -42,7 +42,7 @@ static const char* initWsaData(WSADATA* wsaData) {
closesocket(sockfd);
FF_DEBUG("WinSock initialized successfully");
return NULL;
return nullptr;
}
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers) {
@@ -52,7 +52,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
#ifdef FF_HAVE_ZLIB
const char* zlibError = ffNetworkingLoadZlibLibrary();
// Only enable compression if zlib library is successfully loaded
if (zlibError == NULL) {
if (zlibError == nullptr) {
FF_DEBUG("Successfully loaded zlib library, compression enabled");
} else {
FF_DEBUG("Failed to load zlib library, compression disabled: %s", zlibError);
@@ -69,7 +69,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
static WSADATA wsaData;
if (wsaData.wVersion == 0) {
const char* error = initWsaData(&wsaData);
if (error != NULL) {
if (error != nullptr) {
wsaData.wVersion = (WORD) -1;
FF_DEBUG("WinSock initialization failed: %s", error);
return error;
@@ -87,7 +87,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
};
wchar_t hostW[256];
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(hostW, (ULONG) sizeof(hostW), NULL, host, (ULONG) strlen(host) + 1))) {
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(hostW, (ULONG) sizeof(hostW), nullptr, host, (ULONG) strlen(host) + 1))) {
FF_DEBUG("Failed to convert host to wide string: %s", host);
return "Failed to convert host to wide string";
}
@@ -98,7 +98,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
return "GetAddrInfoW() failed";
}
state->sockfd = WSASocketW(addr->ai_family, addr->ai_socktype, addr->ai_protocol, NULL, 0, 0);
state->sockfd = WSASocketW(addr->ai_family, addr->ai_socktype, addr->ai_protocol, nullptr, 0, 0);
if (state->sockfd == INVALID_SOCKET) {
FF_DEBUG("WSASocketW() failed");
FreeAddrInfoW(addr);
@@ -141,16 +141,14 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
}
// Initialize overlapped structure with WSA event for asynchronous I/O
state->overlapped = (OVERLAPPED) {
.hEvent = WSACreateEvent()
};
state->overlapped = (OVERLAPPED) {};
if (state->overlapped.hEvent == WSA_INVALID_EVENT) {
FF_DEBUG("WSACreateEvent() failed");
if (!NT_SUCCESS(NtCreateEvent(&state->overlapped.hEvent, EVENT_ALL_ACCESS, nullptr, NotificationEvent, FALSE))) {
FF_DEBUG("NtCreateEvent() failed");
closesocket(state->sockfd);
FreeAddrInfoW(addr);
state->sockfd = INVALID_SOCKET;
return "WSACreateEvent() failed";
return "NtCreateEvent() failed";
}
// Build HTTP command
@@ -189,12 +187,12 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
BOOL result = ConnectEx(state->sockfd, addr->ai_addr, (int) addr->ai_addrlen, state->command.chars, state->command.length, &sent, &state->overlapped);
FreeAddrInfoW(addr);
addr = NULL;
addr = nullptr;
if (!result) {
if (WSAGetLastError() != WSA_IO_PENDING) {
FF_DEBUG("ConnectEx() failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
WSACloseEvent(state->overlapped.hEvent);
NtClose(state->overlapped.hEvent);
closesocket(state->sockfd);
state->sockfd = INVALID_SOCKET;
ffStrbufDestroy(&state->command);
@@ -207,7 +205,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
}
// No need to cleanup state fields here since we need them in the receive function
return NULL;
return nullptr;
}
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer) {
@@ -219,40 +217,30 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
return "ffNetworkingSendHttpRequest() failed";
}
DWORD transfer;
uint32_t timeout = state->timeout;
if (timeout > 0) {
FF_DEBUG("WSAWaitForMultipleEvents with timeout: %u ms", timeout);
DWORD result = WSAWaitForMultipleEvents(1, &state->overlapped.hEvent, TRUE, timeout, FALSE);
if (result != WSA_WAIT_EVENT_0) {
if (result == WSA_WAIT_TIMEOUT) {
FF_DEBUG("WSAWaitForMultipleEvents timed out");
} else {
FF_DEBUG("WSAWaitForMultipleEvents failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
}
if (CancelIoEx((HANDLE) state->sockfd, &state->overlapped)) {
WSAWaitForMultipleEvents(1, &state->overlapped.hEvent, TRUE, 10, TRUE);
}
WSACloseEvent(state->overlapped.hEvent);
closesocket(state->sockfd);
ffStrbufDestroy(&state->command);
return "WSAWaitForMultipleEvents() failed or timeout";
if (!GetOverlappedResultEx((HANDLE) state->sockfd, &state->overlapped, &transfer, timeout > 0 ? timeout : INFINITE, FALSE)) {
DWORD error = GetLastError();
if (error == WAIT_TIMEOUT) {
FF_DEBUG("GetOverlappedResultEx timed out");
} else {
FF_DEBUG("GetOverlappedResultEx failed: %s", ffDebugWin32Error(error));
}
}
DWORD transfer, flags;
if (!WSAGetOverlappedResult(state->sockfd, &state->overlapped, &transfer, TRUE, &flags)) {
FF_DEBUG("WSAGetOverlappedResult failed: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
IO_STATUS_BLOCK cancelIosb = {};
if (NT_SUCCESS(NtCancelIoFileEx((HANDLE) state->sockfd, (PIO_STATUS_BLOCK) &state->overlapped, &cancelIosb))) {
NtWaitForSingleObject(state->overlapped.hEvent, TRUE, &(LARGE_INTEGER) { .QuadPart = (int64_t) 10 * -10000 });
}
NtClose(state->overlapped.hEvent);
closesocket(state->sockfd);
WSACloseEvent(state->overlapped.hEvent);
ffStrbufDestroy(&state->command);
return "WSAGetOverlappedResult() failed";
return "GetOverlappedResultEx() failed or timeout";
}
FF_DEBUG("WSAGetOverlappedResult succeeded, %u bytes sent", (unsigned) transfer);
FF_DEBUG("GetOverlappedResultEx succeeded, %u bytes sent", (unsigned) transfer);
ffStrbufDestroy(&state->command);
WSACloseEvent(state->overlapped.hEvent);
state->overlapped.hEvent = NULL;
NtClose(state->overlapped.hEvent);
state->overlapped.hEvent = nullptr;
if (setsockopt(state->sockfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0) != 0) {
if (setsockopt(state->sockfd, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, nullptr, 0) != 0) {
FF_DEBUG("Failed to update connect context: %s", ffDebugWin32Error((DWORD) WSAGetLastError()));
// Not a critical error, continue anyway
}
@@ -275,7 +263,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
}
FF_DEBUG("Starting data reception");
FF_A_UNUSED int recvCount = 0;
[[maybe_unused]] int recvCount = 0;
uint32_t contentLength = 0;
uint32_t headerEnd = 0;
@@ -293,8 +281,8 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
1,
&received,
&recvFlags,
NULL,
NULL);
nullptr,
nullptr);
if (recvResult == SOCKET_ERROR || received == 0) {
if (recvResult == 0 && received == 0) {
@@ -320,8 +308,15 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
// Check for Content-Length header to pre-allocate enough memory
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
if (clHeader) {
contentLength = (uint32_t) strtoul(clHeader + 15, NULL, 10);
contentLength = (uint32_t) strtoul(clHeader + 15, nullptr, 10);
if (contentLength > 0) {
if (contentLength > 1024 * 1024) { // 1MB limit to prevent excessive memory allocation and potential attacks
FF_DEBUG("Content-Length is too large: %u bytes, aborting", contentLength);
closesocket(state->sockfd);
state->sockfd = INVALID_SOCKET;
return "Content-Length too large";
}
FF_DEBUG("Detected Content-Length: %u, pre-allocating buffer", contentLength);
// Ensure buffer is large enough, adding header size and some margin
ffStrbufEnsureFree(buffer, contentLength + 16);
@@ -346,7 +341,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
return "No HTTP header end found";
}
if (!ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
if (!ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n") && !ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n")) {
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
return "Invalid response";
}
@@ -372,5 +367,5 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
}
#endif
return NULL;
return nullptr;
}
+10 -10
View File
@@ -5,19 +5,19 @@
#include <limits.h>
// Return start position of the inner key if the argument key belongs to the module specified, NULL otherwise
// Return start position of the inner key if the argument key belongs to the module specified, nullptr otherwise
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName) {
assert(argumentKey && moduleName);
const char* subKey = argumentKey;
if (!(subKey[0] == '-' && subKey[1] == '-')) {
return NULL;
return nullptr;
}
subKey += 2;
uint32_t moduleNameLen = (uint32_t) strlen(moduleName);
if (strncasecmp(subKey, moduleName, moduleNameLen) != 0) {
return NULL;
return nullptr;
}
subKey += moduleNameLen;
@@ -27,7 +27,7 @@ const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName)
}
if (subKey[0] != '-') {
return NULL;
return nullptr;
}
subKey += 1;
@@ -36,7 +36,7 @@ const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName)
}
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer) {
if (value == NULL) {
if (value == nullptr) {
fprintf(stderr, "Error: usage: %s <str>\n", argumentKey);
exit(477);
}
@@ -45,7 +45,7 @@ void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* b
}
uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value) {
if (value == NULL) {
if (value == nullptr) {
fprintf(stderr, "Error: usage: %s <num>\n", argumentKey);
exit(480);
}
@@ -61,7 +61,7 @@ uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value) {
}
int32_t ffOptionParseInt32(const char* argumentKey, const char* value) {
if (value == NULL) {
if (value == nullptr) {
fprintf(stderr, "Error: usage: %s <num>\n", argumentKey);
exit(480);
}
@@ -77,7 +77,7 @@ int32_t ffOptionParseInt32(const char* argumentKey, const char* value) {
}
int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[]) {
if (requestedKey == NULL) {
if (requestedKey == nullptr) {
fprintf(stderr, "Error: usage: %s <value>\n", argumentKey);
exit(476);
}
@@ -139,7 +139,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer) {
} else if (value[0] == '@') {
// Xterm 256 color
++value;
char* pend = NULL;
char* pend = nullptr;
uint32_t color = (uint32_t) strtoul(value, &pend, 10);
if (pend == value || color > 255) {
fprintf(stderr, "Error: invalid 256 color code found: %s\n", value);
@@ -153,7 +153,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer) {
} else if (value[0] == '#') {
// RGB color
++value;
char* pend = NULL;
char* pend = nullptr;
uint32_t rgb = (uint32_t) strtoul(value, &pend, 16);
if (pend == value) {
fprintf(stderr, "Error: invalid RGB color code found: %s\n", value);
+18 -18
View File
@@ -47,7 +47,7 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) {
}
#endif
return NULL;
return nullptr;
}
ffStrbufClear(result);
return "Executable not found";
@@ -60,13 +60,13 @@ const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) {
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) {
char buffer[MAX_PATH + 1];
DWORD length = SearchPathA(NULL, name, ".exe", sizeof(buffer), buffer, NULL);
DWORD length = SearchPathA(nullptr, name, ".exe", sizeof(buffer), buffer, nullptr);
if (length == 0) {
ffStrbufClear(result);
return "Executable not found";
}
ffStrbufSetS(result, buffer);
return NULL;
return nullptr;
}
static inline int winerr2Errno(DWORD err) {
@@ -93,7 +93,7 @@ static inline int winerr2Errno(DWORD err) {
char* frealpath(HANDLE hFile, char* resolved_name) {
if (__builtin_expect(hFile == INVALID_HANDLE_VALUE || !hFile, false)) {
errno = EINVAL;
return NULL;
return nullptr;
}
wchar_t resolvedNameW[MAX_PATH + 4]; /* +4 for "\\\\?\\" prefix */
@@ -101,11 +101,11 @@ char* frealpath(HANDLE hFile, char* resolved_name) {
if (lenW == 0) {
errno = winerr2Errno(GetLastError());
return NULL;
return nullptr;
}
if (lenW >= ARRAY_SIZE(resolvedNameW)) {
errno = E2BIG;
return NULL;
return nullptr;
}
lenW++; // Include null terminator
@@ -126,7 +126,7 @@ char* frealpath(HANDLE hFile, char* resolved_name) {
ULONG outBytes = 0;
if (!NT_SUCCESS(RtlUnicodeToUTF8N(resolved_name, MAX_PATH, &outBytes, srcW, (ULONG) (srcLenW * sizeof(wchar_t))))) {
errno = E2BIG;
return NULL;
return nullptr;
}
} else {
/* UTF-8 worst-case: up to 4 bytes per UTF-16 code unit */
@@ -135,13 +135,13 @@ char* frealpath(HANDLE hFile, char* resolved_name) {
if (!NT_SUCCESS(RtlUnicodeToUTF8N(tmp, (ULONG) sizeof(tmp), &outBytes, srcW, (ULONG) (srcLenW * sizeof(wchar_t))))) {
errno = E2BIG;
return NULL;
return nullptr;
}
resolved_name = (char*) malloc(outBytes);
if (!resolved_name) {
errno = ENOMEM;
return NULL;
return nullptr;
}
memcpy(resolved_name, tmp, outBytes);
@@ -153,7 +153,7 @@ char* frealpath(HANDLE hFile, char* resolved_name) {
char* realpath(const char* __restrict file_name, char* __restrict resolved_name) {
if (!file_name) {
errno = EINVAL;
return NULL;
return nullptr;
}
wchar_t fileNameW[MAX_PATH];
@@ -161,21 +161,21 @@ char* realpath(const char* __restrict file_name, char* __restrict resolved_name)
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &lenBytes, file_name, (ULONG) strlen(file_name) + 1))) {
errno = EINVAL;
return NULL;
return nullptr;
}
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileW(
fileNameW,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
errno = winerr2Errno(GetLastError());
return NULL;
return nullptr;
}
return frealpath(hFile, resolved_name);
@@ -189,13 +189,13 @@ ssize_t freadlink(HANDLE hFile, char* buf, size_t bufsiz) {
alignas(REPARSE_DATA_BUFFER) BYTE reparseBuf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
DWORD bytesReturned = 0;
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, reparseBuf, (DWORD) sizeof(reparseBuf), &bytesReturned, NULL)) {
if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, reparseBuf, (DWORD) sizeof(reparseBuf), &bytesReturned, nullptr)) {
errno = winerr2Errno(GetLastError());
return -1;
}
REPARSE_DATA_BUFFER* rp = (REPARSE_DATA_BUFFER*) reparseBuf;
const wchar_t* targetW = NULL;
const wchar_t* targetW = nullptr;
USHORT targetBytes = 0;
if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
@@ -262,10 +262,10 @@ ssize_t readlink(const char* path, char* buf, size_t bufsiz) {
pathW,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
nullptr,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
NULL);
nullptr);
if (hFile == INVALID_HANDLE_VALUE) {
errno = winerr2Errno(GetLastError());
+3 -3
View File
@@ -17,7 +17,7 @@ static void appendOutputColor(FFstrbuf* buffer, const FFModuleArgs* module) {
const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFlags* result) {
if (yyjson_is_uint(jsonVal)) {
*result = (FFPercentageTypeFlags) yyjson_get_uint(jsonVal);
return NULL;
return nullptr;
}
if (yyjson_is_arr(jsonVal)) {
FFPercentageTypeFlags flags = 0;
@@ -45,7 +45,7 @@ const char* ffPercentParseTypeJsonConfig(yyjson_val* jsonVal, FFPercentageTypeFl
}
*result = flags;
return NULL;
return nullptr;
}
return "Error: usage: percent.type must be a number or an array of strings";
@@ -90,7 +90,7 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
bool monochrome = (percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT) || !autoColorElapsed;
if (!options->pipe && options->barColorElapsed.length > 0 && monochrome) {
const char* color = NULL;
const char* color = nullptr;
if (!autoColorElapsed) {
color = options->barColorElapsed.chars;
} else if (green <= yellow) {
+3 -3
View File
@@ -7,7 +7,7 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
ffLogoPrintLine();
// This is used by --set-keyless, in this case we want neither the module name nor the separator
if (moduleName == NULL) {
if (moduleName == nullptr) {
return;
}
@@ -35,7 +35,7 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_STRING) {
ffPrintCharTimes(' ', instance.config.display.keyType >> FF_MODULE_KEY_TYPE_SPACE_SHIFT);
// NULL check is required for modules with custom keys, e.g. disk with the folder path
// nullptr check is required for modules with custom keys, e.g. disk with the folder path
if ((printType & FF_PRINT_TYPE_NO_CUSTOM_KEY) || !moduleArgs || moduleArgs->key.length == 0) {
fputs(moduleName, stdout);
@@ -84,7 +84,7 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
bool ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments) {
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
bool success;
if (__builtin_expect(moduleArgs != NULL, 1)) {
if (__builtin_expect(moduleArgs != nullptr, 1)) {
success = ffParseFormatString(&buffer, &moduleArgs->outputFormat, numArgs, arguments);
} else {
ffStrbufSetStatic(&buffer, "undefined format");
+21 -21
View File
@@ -79,7 +79,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
posix_spawn_file_actions_adddup2(&file_actions, pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
posix_spawn_file_actions_adddup2(&file_actions, nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
static char* oldLang = NULL;
static char* oldLang = nullptr;
static int langIndex = -1;
if (langIndex >= 0) {
@@ -95,7 +95,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
}
}
if (langIndex < 0) {
for (int i = 0; environ[i] != NULL; i++) {
for (int i = 0; environ[i] != nullptr; i++) {
if (ffStrStartsWith(environ[i], "LANG=")) {
langIndex = i;
const char* langValue = environ[i] + 5; // Skip "LANG="
@@ -112,7 +112,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
}
}
int ret = posix_spawnp(&childPid, argv[0], &file_actions, NULL, argv, environ);
int ret = posix_spawnp(&childPid, argv[0], &file_actions, nullptr, argv, environ);
if (oldLang) {
environ[langIndex] = oldLang;
@@ -153,7 +153,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
close(pipes[1]);
outHandle->pid = childPid;
outHandle->pipeRead = pipes[0];
return NULL;
return nullptr;
}
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) {
@@ -173,11 +173,11 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) {
int pollret = poll(&pollfd, 1, timeout);
if (pollret == 0) {
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
waitpid(childPid, nullptr, 0);
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
} else if (pollret < 0 || (pollfd.revents & POLLERR)) {
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
waitpid(childPid, nullptr, 0);
return pollret < 0
? "poll(&pollfd, 1, timeout) error: pollret < 0"
: "poll(&pollfd, 1, timeout) error: pollfd.revents & POLLERR";
@@ -197,9 +197,9 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) {
return "command not found";
}
// We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c`
return NULL;
return nullptr;
}
return NULL;
return nullptr;
} else if (nRead < 0) {
break;
}
@@ -278,11 +278,11 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
size_t len = 0;
int mibs[] = { CTL_KERN, KERN_PROCARGS2, pid };
if (sysctl(mibs, ARRAY_SIZE(mibs), NULL, &len, NULL, 0) == 0) { // try get arg0
if (sysctl(mibs, ARRAY_SIZE(mibs), nullptr, &len, nullptr, 0) == 0) { // try get arg0
// don't know why if don't let len longer, proArgs2 and len will change during the following sysctl() in old MacOS version.
len++;
FF_AUTO_FREE char* const procArgs2 = malloc(len);
if (sysctl(mibs, ARRAY_SIZE(mibs), procArgs2, &len, NULL, 0) == 0) {
if (sysctl(mibs, ARRAY_SIZE(mibs), procArgs2, &len, nullptr, 0) == 0) {
// https://gist.github.com/nonowarn/770696#file-getargv-c-L46
uint32_t argc = *(uint32_t*) procArgs2;
const char* realExePath = procArgs2 + sizeof(argc);
@@ -354,7 +354,7 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
4,
args,
&size,
NULL,
nullptr,
0) == 0)
ffStrbufSetNS(exePath, (uint32_t) (size - 1), args);
@@ -374,7 +374,7 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
4,
args,
&size,
NULL,
nullptr,
0) == 0) {
char* arg0 = args;
size_t arg0Len = strlen(args);
@@ -423,7 +423,7 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
#elif defined(__OpenBSD__)
kvm_t* kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
kvm_t* kd = kvm_open(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
int count = 0;
const struct kinfo_proc* proc = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &count);
if (proc) {
@@ -488,7 +488,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
}
buf[nRead] = '\0'; // pid (comm) state ppid pgrp session tty
const char* pState = NULL;
const char* pState = nullptr;
{
// comm in `/proc/pid/stat` is not encoded, and may contain ' ', ')' or even `\n`
@@ -542,7 +542,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
struct kinfo_proc proc;
size_t size = sizeof(proc);
if (sysctl(
(int[]) { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }, 4, &proc, &size, NULL, 0)) {
(int[]) { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }, 4, &proc, &size, nullptr, 0)) {
return "sysctl(KERN_PROC_PID) failed";
}
@@ -568,7 +568,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
struct kinfo_proc proc;
size_t size = sizeof(proc);
if (sysctl(
(int[]) { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }, 4, &proc, &size, NULL, 0)) {
(int[]) { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }, 4, &proc, &size, nullptr, 0)) {
return "sysctl(KERN_PROC_PID) failed";
}
@@ -580,7 +580,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
if (proc.ki_tdev != NODEV && proc.ki_flag & P_CONTROLT) {
const char* ttyName = devname(proc.ki_tdev, S_IFCHR);
if (ffStrStartsWith(ttyName, "pts/")) {
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
*tty = (int32_t) strtol(ttyName + strlen("pts/"), nullptr, 10);
} else {
*tty = -1;
}
@@ -594,7 +594,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
struct kinfo_proc2 proc;
size_t size = sizeof(proc);
if (sysctl(
(int[]) { CTL_KERN, KERN_PROC2, KERN_PROC_PID, pid, sizeof(proc), 1 }, 6, &proc, &size, NULL, 0) != 0) {
(int[]) { CTL_KERN, KERN_PROC2, KERN_PROC_PID, pid, sizeof(proc), 1 }, 6, &proc, &size, nullptr, 0) != 0) {
return "sysctl(KERN_PROC_PID) failed";
}
@@ -606,7 +606,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
if (proc.p_flag & P_CONTROLT) {
const char* ttyName = devname(proc.p_tdev, S_IFCHR);
if (ffStrStartsWith(ttyName, "pts/")) {
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
*tty = (int32_t) strtol(ttyName + strlen("pts/"), nullptr, 10);
} else {
*tty = -1;
}
@@ -633,7 +633,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
#elif defined(__OpenBSD__)
kvm_t* kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, NULL);
kvm_t* kd = kvm_open(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
int count = 0;
const struct kinfo_proc* proc = kvm_getprocs(kd, KERN_PROC_PID, pid, sizeof(struct kinfo_proc), &count);
if (proc) {
@@ -668,5 +668,5 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
#endif
return NULL;
return nullptr;
}
+61 -25
View File
@@ -15,7 +15,7 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result) {
// From https://gist.github.com/jin-x/cdd641d98887524b091fb1f82a68717d
FF_STRBUF_AUTO_DESTROY temp = ffStrbufCreate();
for (int i = 0; argv[i] != NULL; i++) {
for (int i = 0; argv[i] != nullptr; i++) {
ffStrbufSetS(&temp, argv[i]);
// Add slash (\) before double quotes (") and duplicate slashes before it
for (
@@ -48,6 +48,41 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result) {
}
}
static wchar_t* createChildEnvironment(void) {
auto pparams = ffGetPeb()->ProcessParameters;
const wchar_t* readStart = pparams->Environment;
if (!readStart) {
return nullptr;
}
RtlAcquirePebLock();
wchar_t* result = malloc(pparams->EnvironmentSize + sizeof(L"LANG=C.UTF-8"));
const wchar_t* entry = readStart;
wchar_t* writeStart = result;
// Copy all environment variables except LANG
while (*entry) {
assert((const uint8_t*) entry <= (const uint8_t*) pparams->Environment + pparams->EnvironmentSize);
size_t entryLength = wcslen(entry);
if (entryLength >= strlen("LANG=") && memcmp(entry, L"LANG=", strlen("LANG=") * sizeof(wchar_t)) == 0) {
memcpy(writeStart, readStart, (size_t) (entry - readStart) * sizeof(wchar_t));
writeStart += (size_t) (entry - readStart);
readStart = entry + entryLength + 1;
}
entry += entryLength + 1;
}
// Copy the remaining environment variables
memcpy(writeStart, readStart, (size_t) (entry - readStart) * sizeof(wchar_t));
writeStart += (size_t) (entry - readStart);
// Add LANG=C.UTF-8 and double null terminator
memcpy(writeStart, L"LANG=C.UTF-8\0", sizeof(L"LANG=C.UTF-8\0"));
RtlReleasePebLock();
return result;
}
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle) {
const int32_t timeout = instance.config.general.processingTimeout;
@@ -63,7 +98,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
FF_PIPE_BUFSIZ,
FF_PIPE_BUFSIZ,
0,
NULL);
nullptr);
if (hChildPipeRead == INVALID_HANDLE_VALUE) {
return "CreateNamedPipeW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
}
@@ -74,12 +109,12 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
0,
&(SECURITY_ATTRIBUTES) {
.nLength = sizeof(SECURITY_ATTRIBUTES),
.lpSecurityDescriptor = NULL,
.lpSecurityDescriptor = nullptr,
.bInheritHandle = TRUE,
},
OPEN_EXISTING,
0,
NULL);
nullptr);
if (hChildPipeWrite == INVALID_HANDLE_VALUE) {
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
}
@@ -97,28 +132,29 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
siStartInfo.hStdError = ffGetNullFD();
}
FF_AUTO_FREE wchar_t* cmdline = NULL;
FF_AUTO_FREE wchar_t* cmdline = nullptr;
{
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
argvToCmdline(argv, &buf);
uint32_t cmdlineBytes = (buf.length + 1) * sizeof(wchar_t);
cmdline = malloc(cmdlineBytes);
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(cmdline, cmdlineBytes, NULL, buf.chars, buf.length + 1))) {
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(cmdline, cmdlineBytes, nullptr, buf.chars, buf.length + 1))) {
return "RtlUTF8ToUnicodeN() failed";
}
}
FF_AUTO_FREE wchar_t* environment = createChildEnvironment();
BOOL success = CreateProcessW(
NULL, // application name
cmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
nullptr, // application name
cmdline, // command line
nullptr, // process security attributes
nullptr, // primary thread security attributes
TRUE, // handles are inherited
CREATE_UNICODE_ENVIRONMENT, // creation flags
environment, // child environment
nullptr, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo // receives PROCESS_INFORMATION
);
NtClose(hChildPipeWrite);
@@ -134,7 +170,7 @@ const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle*
outHandle->pipeRead = hChildPipeRead;
hChildPipeRead = INVALID_HANDLE_VALUE; // ownership transferred, don't close it
return NULL;
return nullptr;
}
static void terminateChildProcess(HANDLE hProcess, HANDLE hChildPipeRead, HANDLE hReadEvent, IO_STATUS_BLOCK* piosb) {
@@ -154,11 +190,11 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) {
int32_t timeout = instance.config.general.processingTimeout;
FF_AUTO_CLOSE_FD HANDLE hProcess = handle->pid;
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = handle->pipeRead;
FF_AUTO_CLOSE_FD HANDLE hReadEvent = NULL;
FF_AUTO_CLOSE_FD HANDLE hReadEvent = nullptr;
handle->pid = INVALID_HANDLE_VALUE;
handle->pipeRead = INVALID_HANDLE_VALUE;
if (timeout >= 0 && !NT_SUCCESS(NtCreateEvent(&hReadEvent, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE))) {
if (timeout >= 0 && !NT_SUCCESS(NtCreateEvent(&hReadEvent, EVENT_ALL_ACCESS, nullptr, SynchronizationEvent, FALSE))) {
return "NtCreateEvent() failed";
}
@@ -169,13 +205,13 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) {
NTSTATUS status = NtReadFile(
hChildPipeRead,
hReadEvent,
NULL,
NULL,
nullptr,
nullptr,
&iosb,
str,
(ULONG) sizeof(str),
NULL,
NULL);
nullptr,
nullptr);
if (status == STATUS_PENDING) {
switch (NtWaitForSingleObject(hReadEvent, FALSE, &(LARGE_INTEGER) { .QuadPart = (int64_t) timeout * -10000 })) {
case STATUS_WAIT_0:
@@ -198,7 +234,7 @@ const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer) {
}
if (!NT_SUCCESS(status)) {
terminateChildProcess(hProcess, hChildPipeRead, NULL, &iosb);
terminateChildProcess(hProcess, hChildPipeRead, nullptr, &iosb);
return "NtReadFile(hChildPipeRead) failed";
}
@@ -219,7 +255,7 @@ exit: {
}
}
return NULL;
return nullptr;
}
bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui) {
+2 -2
View File
@@ -95,7 +95,7 @@ bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer) {
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries) {
FF_AUTO_CLOSE_FILE FILE* file = fopen(filename, "r");
if (file == NULL) {
if (file == nullptr) {
return false;
}
@@ -115,7 +115,7 @@ bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquer
}
if (!allSet) {
FF_AUTO_FREE char* line = NULL;
FF_AUTO_FREE char* line = nullptr;
size_t len = 0;
while (getline(&line, &len, file) != -1) {
+60 -60
View File
@@ -19,10 +19,10 @@ typedef struct GVariantGetters {
static FFvariant getGVariantValue(GVariant* variant, FFvarianttype type, const GVariantGetters* variantGetters) {
FFvariant result;
if (variant == NULL) {
if (variant == nullptr) {
result = FF_VARIANT_NULL;
} else if (type == FF_VARIANT_TYPE_STRING) {
result = (FFvariant) { .strValue = variantGetters->ffg_variant_dup_string(variant, NULL) }; // Dup string, so that variant itself can be freed
result = (FFvariant) { .strValue = variantGetters->ffg_variant_dup_string(variant, nullptr) }; // Dup string, so that variant itself can be freed
} else if (type == FF_VARIANT_TYPE_BOOL) {
result = (FFvariant) { .boolValue = (bool) variantGetters->ffg_variant_get_boolean(variant), .boolValueSet = true };
} else if (type == FF_VARIANT_TYPE_INT) {
@@ -57,27 +57,27 @@ static const GSettingsData* getGSettingsData(void) {
if (!data.inited) {
data.inited = true;
FF_LIBRARY_LOAD(libgsettings, NULL, "libgio-2.0" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_schema_source_lookup, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_schema_has_key, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_new_full, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_get_value, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_get_user_value, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_get_default_value, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_schema_source_get_default, NULL)
FF_LIBRARY_LOAD(libgsettings, nullptr, "libgio-2.0" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_schema_source_lookup, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_schema_has_key, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_new_full, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_get_value, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_get_user_value, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_get_default_value, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data, g_settings_schema_source_get_default, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_dup_string, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_get_boolean, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_get_int32, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_unref, NULL);
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_dup_string, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_get_boolean, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_get_int32, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libgsettings, data.variantGetters, g_variant_unref, nullptr);
data.schemaSource = data.ffg_settings_schema_source_get_default();
if (data.schemaSource) {
libgsettings = NULL;
libgsettings = nullptr;
}
}
if (!data.schemaSource) {
return NULL;
return nullptr;
}
return &data;
@@ -85,12 +85,12 @@ static const GSettingsData* getGSettingsData(void) {
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type) {
const GSettingsData* data = getGSettingsData();
if (data == NULL) {
if (data == nullptr) {
return FF_VARIANT_NULL;
}
GSettingsSchema* schema = data->ffg_settings_schema_source_lookup(data->schemaSource, schemaName, true);
if (schema == NULL) {
if (schema == nullptr) {
return FF_VARIANT_NULL;
}
@@ -98,18 +98,18 @@ FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const
return FF_VARIANT_NULL;
}
GSettings* settings = data->ffg_settings_new_full(schema, NULL, path);
if (settings == NULL) {
GSettings* settings = data->ffg_settings_new_full(schema, nullptr, path);
if (settings == nullptr) {
return FF_VARIANT_NULL;
}
GVariant* variant = data->ffg_settings_get_value(settings, key);
if (variant != NULL) {
if (variant != nullptr) {
return getGVariantValue(variant, type, &data->variantGetters);
}
variant = data->ffg_settings_get_user_value(settings, key);
if (variant != NULL) {
if (variant != nullptr) {
return getGVariantValue(variant, type, &data->variantGetters);
}
@@ -141,21 +141,21 @@ static const DConfData* getDConfData(void) {
if (!data.inited) {
data.inited = true;
FF_LIBRARY_LOAD(libdconf, NULL, "libdconf" FF_LIBRARY_EXTENSION, 2);
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data, dconf_client_read_full, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data, dconf_client_new, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_dup_string, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_get_boolean, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_get_int32, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_unref, NULL)
FF_LIBRARY_LOAD(libdconf, nullptr, "libdconf" FF_LIBRARY_EXTENSION, 2);
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data, dconf_client_read_full, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data, dconf_client_new, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_dup_string, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_get_boolean, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_get_int32, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libdconf, data.variantGetters, g_variant_unref, nullptr)
data.client = data.ffdconf_client_new();
if (data.client) {
libdconf = NULL;
libdconf = nullptr;
}
}
if (!data.client) {
return NULL;
return nullptr;
}
return &data;
@@ -163,21 +163,21 @@ static const DConfData* getDConfData(void) {
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type) {
const DConfData* data = getDConfData();
if (data == NULL) {
if (data == nullptr) {
return FF_VARIANT_NULL;
}
GVariant* variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_FLAGS_NONE, NULL);
if (variant != NULL) {
GVariant* variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_FLAGS_NONE, nullptr);
if (variant != nullptr) {
return getGVariantValue(variant, type, &data->variantGetters);
}
variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_USER_VALUE, NULL);
if (variant != NULL) {
variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_USER_VALUE, nullptr);
if (variant != nullptr) {
return getGVariantValue(variant, type, &data->variantGetters);
}
variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_DEFAULT_VALUE, NULL);
variant = data->ffdconf_client_read_full(data->client, key, DCONF_READ_DEFAULT_VALUE, nullptr);
return getGVariantValue(variant, type, &data->variantGetters);
}
#else // FF_HAVE_DCONF
@@ -192,7 +192,7 @@ FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaNa
if (
(type == FF_VARIANT_TYPE_BOOL && gsettings.boolValueSet) ||
(type != FF_VARIANT_TYPE_BOOL && gsettings.strValue != NULL)) {
(type != FF_VARIANT_TYPE_BOOL && gsettings.strValue != nullptr)) {
return gsettings;
}
@@ -204,7 +204,7 @@ FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaNa
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type) {
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) {
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != nullptr) {
return FF_VARIANT_NULL;
}
@@ -260,7 +260,7 @@ FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName,
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb) {
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) {
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != nullptr) {
return FF_VARIANT_NULL;
}
@@ -361,20 +361,20 @@ static const SQLiteData* getSQLiteData(void) {
if (!data.inited) {
data.inited = true;
FF_LIBRARY_LOAD(libsqlite, NULL, "libsqlite3" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_open_v2, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_prepare_v2, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_step, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_data_count, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_column_int, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_column_text, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_finalize, NULL)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_close, NULL)
libsqlite = NULL;
FF_LIBRARY_LOAD(libsqlite, nullptr, "libsqlite3" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_open_v2, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_prepare_v2, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_step, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_data_count, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_column_int, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_column_text, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_finalize, nullptr)
FF_LIBRARY_LOAD_SYMBOL_VAR(libsqlite, data, sqlite3_close, nullptr)
libsqlite = nullptr;
}
if (!data.ffsqlite3_close) {
return NULL;
return nullptr;
}
return &data;
@@ -386,17 +386,17 @@ int ffSettingsGetSQLite3Int(const char* dbPath, const char* query) {
}
const SQLiteData* data = getSQLiteData();
if (data == NULL) {
if (data == nullptr) {
return 0;
}
sqlite3* db;
if (data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX, NULL) != SQLITE_OK) {
if (data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY | SQLITE_OPEN_NOMUTEX, nullptr) != SQLITE_OK) {
return 0;
}
sqlite3_stmt* stmt;
if (data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, NULL) != SQLITE_OK) {
if (data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, nullptr) != SQLITE_OK) {
data->ffsqlite3_close(db);
return 0;
}
@@ -421,17 +421,17 @@ bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf*
}
const SQLiteData* data = getSQLiteData();
if (data == NULL) {
if (data == nullptr) {
return false;
}
sqlite3* db;
if (data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) {
if (data->ffsqlite3_open_v2(dbPath, &db, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) {
return false;
}
sqlite3_stmt* stmt;
if (data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, NULL) != SQLITE_OK) {
if (data->ffsqlite3_prepare_v2(db, query, (int) strlen(query), &stmt, nullptr) != SQLITE_OK) {
data->ffsqlite3_close(db);
return false;
}
@@ -514,12 +514,12 @@ typedef struct E_Config {
#define FF_EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct_type, member, type) \
do { \
struct_type ___ett; \
ffeet_data_descriptor_element_add(edd, #member, type, EET_G_UNKNOWN, (char*) (&(___ett.member)) - (char*) (&(___ett)), 0, /* 0, */ NULL, NULL); \
ffeet_data_descriptor_element_add(edd, #member, type, EET_G_UNKNOWN, (char*) (&(___ett.member)) - (char*) (&(___ett)), 0, /* 0, */ nullptr, nullptr); \
} while (0)
#define FF_EET_DATA_DESCRIPTOR_ADD_LIST(edd, struct_type, member, subtype) \
do { \
struct_type ___ett; \
ffeet_data_descriptor_element_add(edd, #member, EET_T_UNKNOW, EET_G_LIST, (char*) (&(___ett.member)) - (char*) (&(___ett)), 0, /* 0, */ NULL, subtype); \
ffeet_data_descriptor_element_add(edd, #member, EET_T_UNKNOW, EET_G_LIST, (char*) (&(___ett.member)) - (char*) (&(___ett)), 0, /* 0, */ nullptr, subtype); \
} while (0)
bool ffSettingsGetEnlightenmentProperty(ffEnlightenmentSettings* result) {
@@ -603,7 +603,7 @@ bool ffSettingsGetEnlightenmentProperty(ffEnlightenmentSettings* result) {
return !!parsed;
}
#else
bool ffSettingsGetEnlightenmentProperty(FF_A_UNUSED ffEnlightenmentSettings* result) {
bool ffSettingsGetEnlightenmentProperty([[maybe_unused]] ffEnlightenmentSettings* result) {
return false;
}
#endif
+4 -4
View File
@@ -27,16 +27,16 @@ void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result) {
const FFOptionsDisplay* options = &instance.config.display;
switch (options->sizeBinaryPrefix) {
case FF_SIZE_BINARY_PREFIX_TYPE_IEC:
appendNum(result, bytes, 1024, (const char*[]) { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL });
appendNum(result, bytes, 1024, (const char*[]) { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", nullptr });
break;
case FF_SIZE_BINARY_PREFIX_TYPE_SI:
appendNum(result, bytes, 1000, (const char*[]) { "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL });
appendNum(result, bytes, 1000, (const char*[]) { "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", nullptr });
break;
case FF_SIZE_BINARY_PREFIX_TYPE_JEDEC:
appendNum(result, bytes, 1024, (const char*[]) { "B", "KB", "MB", "GB", "TB", NULL });
appendNum(result, bytes, 1024, (const char*[]) { "B", "KB", "MB", "GB", "TB", nullptr });
break;
default:
appendNum(result, bytes, 1024, (const char*[]) { "B", NULL });
appendNum(result, bytes, 1024, (const char*[]) { "B", nullptr });
break;
}
}
+25 -25
View File
@@ -63,10 +63,10 @@ const FFSmbiosHeader* ffSmbiosNextEntry(const FFSmbiosHeader* header) {
}
static bool parseSmbiosTable(const uint8_t* data, uint32_t length) {
const FFSmbiosHeader* endOfTable = NULL;
const FFSmbiosHeader* endOfTable = nullptr;
FF_DEBUG("Parsing SMBIOS table structures with length %u bytes", length);
FF_A_UNUSED int structureCount = 0, totalCount = 0;
[[maybe_unused]] int structureCount = 0, totalCount = 0;
for (
const FFSmbiosHeader* header = (const FFSmbiosHeader*) data;
(const uint8_t*) header + sizeof(FFSmbiosHeader) < (const uint8_t*) data + length;
@@ -214,7 +214,7 @@ static bool readPhysicalMemory(int fd, off_t address, size_t length, void* buffe
size_t pageOffset = (size_t) (address - alignedAddress);
size_t mapLength = pageOffset + length;
void* p = mmap(NULL, mapLength, PROT_READ, MAP_SHARED, fd, alignedAddress);
void* p = mmap(nullptr, mapLength, PROT_READ, MAP_SHARED, fd, alignedAddress);
if (p == MAP_FAILED) {
FF_DEBUG("mmap failed at aligned address 0x%lx for %zu bytes: %s",
(unsigned long) alignedAddress,
@@ -228,7 +228,7 @@ static bool readPhysicalMemory(int fd, off_t address, size_t length, void* buffe
return true;
}
typedef struct FFSmbios20EntryPoint {
typedef struct [[gnu::packed]] FFSmbios20EntryPoint {
uint8_t AnchorString[4];
uint8_t EntryPointStructureChecksum;
uint8_t EntryPointLength;
@@ -243,11 +243,11 @@ typedef struct FFSmbios20EntryPoint {
uint32_t StructureTableAddress;
uint16_t NumberOfSmbiosStructures;
uint8_t SmbiosBcdRevision;
} FF_A_PACKED FFSmbios20EntryPoint;
} FFSmbios20EntryPoint;
static_assert(offsetof(FFSmbios20EntryPoint, SmbiosBcdRevision) == 0x1E,
"FFSmbios20EntryPoint: Wrong struct alignment");
typedef struct FFSmbios30EntryPoint {
typedef struct [[gnu::packed]] FFSmbios30EntryPoint {
uint8_t AnchorString[5];
uint8_t EntryPointStructureChecksum;
uint8_t EntryPointLength;
@@ -258,7 +258,7 @@ typedef struct FFSmbios30EntryPoint {
uint8_t Reversed;
uint32_t StructureTableMaximumSize;
uint64_t StructureTableAddress;
} FF_A_PACKED FFSmbios30EntryPoint;
} FFSmbios30EntryPoint;
static_assert(offsetof(FFSmbios30EntryPoint, StructureTableAddress) == 0x10,
"FFSmbios30EntryPoint: Wrong struct alignment");
@@ -457,7 +457,7 @@ static bool fillTableBufferPlatform(FFstrbuf* buffer) {
} while (address < lineEnd && (*address == ' ' || *address == '\t'));
errno = 0;
char* addressEnd = NULL;
char* addressEnd = nullptr;
unsigned long long parsedAddress = strtoull(address, &addressEnd, 16);
if (errno != 0 || addressEnd == address || parsedAddress == 0) {
FF_DEBUG("Failed to parse OpenBSD SMBIOS table address from line: %.*s",
@@ -541,7 +541,7 @@ static bool fillTableBufferPlatform(FFstrbuf* buffer) {
}
#endif
off_t entryAddress = (off_t) strtol(strEntryAddress.chars, NULL, 16);
off_t entryAddress = (off_t) strtol(strEntryAddress.chars, nullptr, 16);
if (entryAddress == 0) {
FF_DEBUG("Invalid SMBIOS entry address: 0");
return false;
@@ -671,7 +671,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
if (!fillTableBufferFallback(&buffer)) {
FF_DEBUG("Fallback SMBIOS retrieval also failed");
ffStrbufDestroy(&buffer);
return NULL;
return nullptr;
}
}
@@ -682,7 +682,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
if (buffer.length == 0) {
FF_DEBUG("No valid SMBIOS data available");
return NULL;
return nullptr;
}
return &smbiosTable;
@@ -717,13 +717,13 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
NtQuerySystemInformation(SystemFirmwareTableInformation, &sfti, sizeof(sfti), &bufSize);
if (bufSize <= sizeof(FFRawSmbiosData) + sizeof(sfti)) {
FF_DEBUG("Invalid firmware table size: %lu (must be > %zu)", bufSize, sizeof(FFRawSmbiosData) + sizeof(sfti));
return NULL;
return nullptr;
}
if (bufSize != sfti.TableBufferLength + (ULONG) sizeof(sfti)) {
FF_DEBUG("Firmware table size mismatch: NtQuerySystemInformation returned %lu but expected %lu",
bufSize,
sfti.TableBufferLength + (ULONG) sizeof(sfti));
return NULL;
return nullptr;
}
FF_DEBUG("Firmware table size: %lu bytes", bufSize);
@@ -734,8 +734,8 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
if (!NT_SUCCESS(NtQuerySystemInformation(SystemFirmwareTableInformation, buffer, bufSize, &bufSize))) {
FF_DEBUG("NtQuerySystemInformation(SystemFirmwareTableInformation) failed");
free(buffer);
buffer = NULL;
return NULL;
buffer = nullptr;
return nullptr;
}
FFRawSmbiosData* rawData = (FFRawSmbiosData*) buffer->TableBuffer;
@@ -746,14 +746,14 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
if (!parseSmbiosTable(rawData->SMBIOSTableData, rawData->Length)) {
free(buffer);
buffer = NULL;
return NULL;
buffer = nullptr;
return nullptr;
}
}
if (!buffer) {
FF_DEBUG("No valid SMBIOS data available");
return NULL;
return nullptr;
}
return &smbiosTable;
}
@@ -771,33 +771,33 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() {
if (!registryEntry) {
FF_DEBUG("IOServiceGetMatchingService() failed to find AppleSMBIOS");
return NULL;
return nullptr;
}
FF_DEBUG("AppleSMBIOS service found, retrieving SMBIOS data");
smbiosDataBuffer = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("SMBIOS"), kCFAllocatorDefault, kNilOptions);
if (!smbiosDataBuffer) {
FF_DEBUG("IORegistryEntryCreateCFProperty() failed to get SMBIOS data");
return NULL;
return nullptr;
}
if (CFGetTypeID(smbiosDataBuffer) != CFDataGetTypeID()) {
FF_DEBUG("Unexpected SMBIOS data type: expected CFData");
CFRelease(smbiosDataBuffer);
smbiosDataBuffer = NULL;
return NULL;
smbiosDataBuffer = nullptr;
return nullptr;
}
FF_DEBUG("Successfully retrieved SMBIOS data: %lu bytes", CFDataGetLength(smbiosDataBuffer));
if (!parseSmbiosTable((const uint8_t*) CFDataGetBytePtr(smbiosDataBuffer), (uint32_t) CFDataGetLength(smbiosDataBuffer))) {
CFRelease(smbiosDataBuffer);
smbiosDataBuffer = NULL;
return NULL;
smbiosDataBuffer = nullptr;
return nullptr;
}
}
if (!smbiosDataBuffer) {
FF_DEBUG("No valid SMBIOS data available");
return NULL;
return nullptr;
}
return &smbiosTable;
+1
View File
@@ -1,4 +1,5 @@
#include "common/strutil.h"
#include "common/wcwidth.h"
uint8_t ffUtf8CharLenWidth(const char* str, uint32_t length, uint8_t* width) {
if (__builtin_expect(length == 0 || *str == '\0', false)) {
+14 -14
View File
@@ -5,26 +5,26 @@
#ifdef __OpenBSD__
const char* ffSysctlGetString(int mib1, int mib2, FFstrbuf* result) {
size_t neededLength;
if (sysctl((int[]) { mib1, mib2 }, 2, NULL, &neededLength, NULL, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator
if (sysctl((int[]) { mib1, mib2 }, 2, nullptr, &neededLength, nullptr, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator
return "sysctl() length query failed";
}
ffStrbufEnsureFree(result, (uint32_t) neededLength - 1);
if (sysctl((int[]) { mib1, mib2 }, 2, result->chars + result->length, &neededLength, NULL, 0) != 0) {
if (sysctl((int[]) { mib1, mib2 }, 2, result->chars + result->length, &neededLength, nullptr, 0) != 0) {
return "sysctl() failed to retrieve string data";
}
result->length += (uint32_t) neededLength - 1;
result->chars[result->length] = '\0';
return NULL;
return nullptr;
}
int ffSysctlGetInt(int mib1, int mib2, int defaultValue) {
int result;
size_t neededLength = sizeof(result);
if (sysctl((int[]) { mib1, mib2 }, 2, &result, &neededLength, NULL, 0) != 0) {
if (sysctl((int[]) { mib1, mib2 }, 2, &result, &neededLength, nullptr, 0) != 0) {
return defaultValue;
}
return result;
@@ -33,7 +33,7 @@ int ffSysctlGetInt(int mib1, int mib2, int defaultValue) {
int64_t ffSysctlGetInt64(int mib1, int mib2, int64_t defaultValue) {
int64_t result;
size_t neededLength = sizeof(result);
if (sysctl((int[]) { mib1, mib2 }, 2, &result, &neededLength, NULL, 0) != 0) {
if (sysctl((int[]) { mib1, mib2 }, 2, &result, &neededLength, nullptr, 0) != 0) {
return defaultValue;
}
return result;
@@ -41,13 +41,13 @@ int64_t ffSysctlGetInt64(int mib1, int mib2, int64_t defaultValue) {
#else
const char* ffSysctlGetString(const char* propName, FFstrbuf* result) {
size_t neededLength;
if (sysctlbyname(propName, NULL, &neededLength, NULL, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator
if (sysctlbyname(propName, nullptr, &neededLength, nullptr, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator
return "sysctlbyname() failed";
}
ffStrbufEnsureFree(result, (uint32_t) neededLength - 1);
if (sysctlbyname(propName, result->chars + result->length, &neededLength, NULL, 0) != 0) {
if (sysctlbyname(propName, result->chars + result->length, &neededLength, nullptr, 0) != 0) {
return "sysctlbyname() failed to retrieve string data";
}
@@ -55,13 +55,13 @@ const char* ffSysctlGetString(const char* propName, FFstrbuf* result) {
result->chars[result->length] = '\0';
return NULL;
return nullptr;
}
int ffSysctlGetInt(const char* propName, int defaultValue) {
int result;
size_t neededLength = sizeof(result);
if (sysctlbyname(propName, &result, &neededLength, NULL, 0) != 0) {
if (sysctlbyname(propName, &result, &neededLength, nullptr, 0) != 0) {
return defaultValue;
}
return result;
@@ -70,7 +70,7 @@ int ffSysctlGetInt(const char* propName, int defaultValue) {
int64_t ffSysctlGetInt64(const char* propName, int64_t defaultValue) {
int64_t result;
size_t neededLength = sizeof(result);
if (sysctlbyname(propName, &result, &neededLength, NULL, 0) != 0) {
if (sysctlbyname(propName, &result, &neededLength, nullptr, 0) != 0) {
return defaultValue;
}
return result;
@@ -78,15 +78,15 @@ int64_t ffSysctlGetInt64(const char* propName, int64_t defaultValue) {
#endif // OpenBSD
void* ffSysctlGetData(int* request, u_int requestLength, size_t* resultLength) {
if (sysctl(request, requestLength, NULL, resultLength, NULL, 0) != 0) {
return NULL;
if (sysctl(request, requestLength, nullptr, resultLength, nullptr, 0) != 0) {
return nullptr;
}
void* data = malloc(*resultLength);
if (sysctl(request, requestLength, data, resultLength, NULL, 0) != 0) {
if (sysctl(request, requestLength, data, resultLength, nullptr, 0) != 0) {
free(data);
return NULL;
return nullptr;
}
return data;
+1 -1
View File
@@ -89,7 +89,7 @@ FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs) {
#ifdef _WIN32
double ffQpcMultiplier;
__attribute__((constructor)) static void ffTimeInitQpcMultiplier(void) {
[[gnu::constructor]] static void ffTimeInitQpcMultiplier(void) {
LARGE_INTEGER frequency;
RtlQueryPerformanceFrequency(&frequency);
ffQpcMultiplier = 1000. / (double) frequency.QuadPart;
+8 -8
View File
@@ -30,7 +30,7 @@ static struct trace_event {
} events[4 * 1024 * 1024]; // 4M events, 96 MiB memory usage
static _Atomic uint32_t event_count;
__attribute__((no_instrument_function, always_inline)) static inline uint64_t get_time_us() {
[[gnu::no_instrument_function, gnu::always_inline]] static inline uint64_t get_time_us() {
#if !_WIN32
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -43,12 +43,12 @@ __attribute__((no_instrument_function, always_inline)) static inline uint64_t ge
}
#if _WIN32
__attribute__((constructor, no_instrument_function)) void trace_init() {
[[gnu::constructor, gnu::no_instrument_function]] void trace_init() {
QueryPerformanceFrequency(&freq);
}
#endif
__attribute__((destructor, no_instrument_function)) void trace_fini() {
[[gnu::destructor, gnu::no_instrument_function]] void trace_fini() {
#if _WIN32
uint32_t pid = (uint32_t) GetCurrentProcessId();
#else
@@ -67,10 +67,10 @@ __attribute__((destructor, no_instrument_function)) void trace_fini() {
#if _WIN32
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
SymInitialize(NtCurrentProcess(), NULL, TRUE);
SymInitialize(NtCurrentProcess(), nullptr, TRUE);
#endif
const char* fnName = NULL;
const char* fnName = nullptr;
uint32_t count = atomic_load_explicit(&event_count, memory_order_acquire);
for (uint32_t i = 0; i < count; ++i) {
@@ -115,7 +115,7 @@ __attribute__((destructor, no_instrument_function)) void trace_fini() {
#endif
}
__attribute__((no_instrument_function)) static void write_event(void* this_fn, bool is_exit) {
[[gnu::no_instrument_function]] static void write_event(void* this_fn, bool is_exit) {
uint32_t idx = atomic_fetch_add_explicit(&event_count, 1, memory_order_relaxed);
if (__builtin_expect(idx >= sizeof(events) / sizeof(events[0]), false)) {
abort();
@@ -137,12 +137,12 @@ __attribute__((no_instrument_function)) static void write_event(void* this_fn, b
}
}
__attribute__((no_instrument_function)) void __cyg_profile_func_enter(void* this_fn, void* call_site) {
[[gnu::no_instrument_function]] void __cyg_profile_func_enter(void* this_fn, void* call_site) {
(void) call_site;
write_event(this_fn, false);
}
__attribute__((no_instrument_function)) void __cyg_profile_func_exit(void* this_fn, void* call_site) {
[[gnu::no_instrument_function]] void __cyg_profile_func_exit(void* this_fn, void* call_site) {
(void) call_site;
write_event(this_fn, true);
}
+40 -39
View File
@@ -40,17 +40,16 @@ HANDLE openat(HANDLE dfd, const char* fileName, int oflag);
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory);
#endif
FF_A_ALWAYS_INLINE
static inline bool ffIsValidNativeFD(FFNativeFD fd) {
#ifndef _WIN32
return fd >= 0;
#else
// https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
return fd != INVALID_HANDLE_VALUE && fd != NULL;
return fd != INVALID_HANDLE_VALUE && fd != nullptr;
#endif
}
FF_A_ALWAYS_INLINE FF_A_NONNULL(1)
[[gnu::always_inline, gnu::nonnull(1)]]
static inline void wrapClose(FFNativeFD* pfd) {
assert(pfd);
@@ -62,7 +61,7 @@ static inline void wrapClose(FFNativeFD* pfd) {
#endif
}
}
#define FF_AUTO_CLOSE_FD FF_A_CLEANUP(wrapClose)
#define FF_AUTO_CLOSE_FD [[gnu::cleanup(wrapClose)]]
static inline FFNativeFD FFUnixFD2NativeFD(int unixfd) {
#ifndef _WIN32
@@ -72,31 +71,36 @@ static inline FFNativeFD FFUnixFD2NativeFD(int unixfd) {
#endif
}
FF_A_NONNULL(3) static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* data) {
[[gnu::nonnull(3)]]
static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* data) {
#ifndef _WIN32
return write(fd, data, dataSize) != -1;
#else
DWORD written;
return WriteFile(fd, data, (DWORD) dataSize, &written, NULL) && written == dataSize;
return WriteFile(fd, data, (DWORD) dataSize, &written, nullptr) && written == dataSize;
#endif
}
FF_A_NONNULL(2) static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content) {
[[gnu::nonnull(2)]]
static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content) {
return ffWriteFDData(fd, content->length, content->chars);
}
FF_A_NONNULL(1, 3) bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data);
[[gnu::nonnull(1, 3)]]
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data);
FF_A_NONNULL(1, 2) static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer) {
[[gnu::nonnull(1, 2)]]
static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer) {
return ffWriteFileData(fileName, buffer->length, buffer->chars);
}
FF_A_NONNULL(3) static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data) {
[[gnu::nonnull(3)]]
static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data) {
#ifndef _WIN32
return read(fd, data, dataSize);
#else
DWORD bytesRead;
if (!ReadFile(fd, data, (DWORD) dataSize, &bytesRead, NULL)) {
if (!ReadFile(fd, data, (DWORD) dataSize, &bytesRead, nullptr)) {
return -1;
}
@@ -104,14 +108,14 @@ FF_A_NONNULL(3) static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSiz
#endif
}
FF_A_NONNULL(2) bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
[[gnu::nonnull(2)]] bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
FF_A_NONNULL(1, 3) static inline ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data) {
FFNativeFD FF_AUTO_CLOSE_FD fd =
[[gnu::nonnull(1, 3)]] static inline ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data) {
FF_AUTO_CLOSE_FD FFNativeFD fd =
#ifndef _WIN32
open(fileName, O_RDONLY | O_CLOEXEC);
#else
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
#endif
if (!ffIsValidNativeFD(fd)) {
@@ -121,8 +125,8 @@ FF_A_NONNULL(1, 3) static inline ssize_t ffReadFileData(const char* fileName, si
return ffReadFDData(fd, dataSize, data);
}
FF_A_NONNULL(2, 4) static inline ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data) {
FFNativeFD FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
[[gnu::nonnull(2, 4)]] static inline ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data) {
FF_AUTO_CLOSE_FD FFNativeFD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
if (!ffIsValidNativeFD(fd)) {
return -1;
}
@@ -130,12 +134,12 @@ FF_A_NONNULL(2, 4) static inline ssize_t ffReadFileDataRelative(FFNativeFD dfd,
return ffReadFDData(fd, dataSize, data);
}
FF_A_NONNULL(1, 2) static inline bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer) {
FFNativeFD FF_AUTO_CLOSE_FD fd =
[[gnu::nonnull(1, 2)]] static inline bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer) {
FF_AUTO_CLOSE_FD FFNativeFD fd =
#ifndef _WIN32
open(fileName, O_RDONLY | O_CLOEXEC);
#else
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
#endif
if (!ffIsValidNativeFD(fd)) {
@@ -145,8 +149,8 @@ FF_A_NONNULL(1, 2) static inline bool ffAppendFileBuffer(const char* fileName, F
return ffAppendFDBuffer(fd, buffer);
}
FF_A_NONNULL(2, 3) static inline bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer) {
FFNativeFD FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
[[gnu::nonnull(2, 3)]] static inline bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer) {
FF_AUTO_CLOSE_FD FFNativeFD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
if (!ffIsValidNativeFD(fd)) {
return false;
}
@@ -154,33 +158,32 @@ FF_A_NONNULL(2, 3) static inline bool ffAppendFileBufferRelative(FFNativeFD dfd,
return ffAppendFDBuffer(fd, buffer);
}
FF_A_NONNULL(2) static inline bool ffReadFDBuffer(FFNativeFD fd, FFstrbuf* buffer) {
[[gnu::nonnull(2)]] static inline bool ffReadFDBuffer(FFNativeFD fd, FFstrbuf* buffer) {
ffStrbufClear(buffer);
return ffAppendFDBuffer(fd, buffer);
}
FF_A_NONNULL(1, 2) static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer) {
[[gnu::nonnull(1, 2)]] static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer) {
ffStrbufClear(buffer);
return ffAppendFileBuffer(fileName, buffer);
}
FF_A_NONNULL(2, 3) static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer) {
[[gnu::nonnull(2, 3)]] static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer) {
ffStrbufClear(buffer);
return ffAppendFileBufferRelative(dfd, fileName, buffer);
}
typedef enum FF_A_PACKED FFPathType {
typedef enum FFPathType: uint8_t {
FF_PATHTYPE_FILE = 1 << 0,
FF_PATHTYPE_DIRECTORY = 1 << 1,
FF_PATHTYPE_ANY = FF_PATHTYPE_FILE | FF_PATHTYPE_DIRECTORY,
FF_PATHTYPE_FORCE_UNSIGNED = UINT8_MAX,
} FFPathType;
FF_A_NONNULL(1) static inline bool ffPathExists(const char* path, FFPathType pathType) {
[[gnu::nonnull(1)]] static inline bool ffPathExists(const char* path, FFPathType pathType) {
#ifdef _WIN32
wchar_t wPath[MAX_PATH];
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(wPath, (ULONG) sizeof(wPath), NULL, path, (ULONG) strlen(path) + 1))) {
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(wPath, (ULONG) sizeof(wPath), nullptr, path, (ULONG) strlen(path) + 1))) {
return false;
}
@@ -225,13 +228,11 @@ FF_A_NONNULL(1) static inline bool ffPathExists(const char* path, FFPathType pat
return false;
}
FF_A_NONNULL(1, 2) bool ffPathExpandEnv(const char* in, FFstrbuf* out);
[[gnu::nonnull(1, 2)]] bool ffPathExpandEnv(const char* in, FFstrbuf* out);
#define FF_IO_TERM_RESP_WAIT_MS 100 // #554
FF_A_SCANF(3, 4)
FF_A_NONNULL(1, 3)
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...);
[[gnu::format(scanf, 3, 4), gnu::nonnull(1, 3)]] const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...);
// Not thread safe!
bool ffSuppressIO(bool suppress);
@@ -244,19 +245,19 @@ static inline void ffUnsuppressIO(bool* suppressed) {
*suppressed = false;
}
#define FF_SUPPRESS_IO() bool FF_A_CLEANUP(ffUnsuppressIO) FF_A_UNUSED io_suppressed__ = ffSuppressIO(true)
#define FF_SUPPRESS_IO() [[maybe_unused, gnu::cleanup(ffUnsuppressIO)]] bool io_suppressed__ = ffSuppressIO(true)
void ffListFilesRecursively(const char* path, bool pretty);
FF_A_NONNULL(1) FF_A_ALWAYS_INLINE static inline void wrapFclose(FILE** pfile) {
[[gnu::nonnull(1), gnu::always_inline]] static inline void wrapFclose(FILE** pfile) {
assert(pfile);
if (*pfile) {
fclose(*pfile);
}
}
#define FF_AUTO_CLOSE_FILE FF_A_CLEANUP(wrapFclose)
#define FF_AUTO_CLOSE_FILE [[gnu::cleanup(wrapFclose)]]
FF_A_NONNULL(1) FF_A_ALWAYS_INLINE
[[gnu::nonnull(1), gnu::always_inline]]
#ifndef _WIN32
static inline void wrapClosedir(DIR** pdir) {
assert(pdir);
@@ -272,9 +273,9 @@ static inline void wrapClosedir(HANDLE* pdir) {
}
}
#endif
#define FF_AUTO_CLOSE_DIR FF_A_CLEANUP(wrapClosedir)
#define FF_AUTO_CLOSE_DIR [[gnu::cleanup(wrapClosedir)]]
FF_A_NONNULL(1, 2, 3) static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result) {
[[gnu::nonnull(1, 2, 3)]] static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result) {
// configDirs is a list of FFstrbufs include the trailing slash
FF_LIST_FOR_EACH (FFstrbuf, dir, *configDirs) {
ffStrbufClear(result);

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