mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
224 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16b6aac764 | |||
| 9f5046d69f | |||
| cace1a7156 | |||
| 9c0cf863ba | |||
| ffe55d9eee | |||
| 28bc9523d6 | |||
| ebf810ad4b | |||
| 5c9a0a1f88 | |||
| bc05a30724 | |||
| 98c7803a24 | |||
| 0893013e78 | |||
| e6985a8832 | |||
| 7a87638fec | |||
| 00f163be32 | |||
| 68bbb2980e | |||
| dd1a799abb | |||
| 7611d672b7 | |||
| bfb93cd8f5 | |||
| 0998b1e59e | |||
| 588c4c0026 | |||
| a80ea2b117 | |||
| 13110e3074 | |||
| 0b2c0445c0 | |||
| 062963d6cc | |||
| 4b7f231b5a | |||
| 74e0732390 | |||
| e9104c38c6 | |||
| 4a7b3a8493 | |||
| 20fafa5a21 | |||
| 1d32344cf7 | |||
| 82a1eaf276 | |||
| 75a023f4d7 | |||
| 53424300e3 | |||
| d553bc4893 | |||
| add2bfd108 | |||
| e508100a15 | |||
| 1a2f4b4c1f | |||
| e968bca89d | |||
| 71fbe04367 | |||
| f2f9b10b18 | |||
| fae4892643 | |||
| 8589bf2392 | |||
| 8b18e69980 | |||
| 9ae968fbd3 | |||
| 8f6608db74 | |||
| 45b6a333ec | |||
| 5012bc250b | |||
| 5775409cb9 | |||
| 64da80d520 | |||
| 8b1bfcb34b | |||
| 784a7a92c8 | |||
| 8331242f42 | |||
| 79fea61c90 | |||
| a8e7d38afd | |||
| 24467e8c46 | |||
| 6867b87c3e | |||
| cb13d43a7a | |||
| bd7190ca6d | |||
| 49982588cf | |||
| de2dff5da0 | |||
| b05c54486f | |||
| 1f1d7cf936 | |||
| 26253f8863 | |||
| 08e6db090b | |||
| ec0fa89cc8 | |||
| 7f48500cfd | |||
| a7eecf6fc7 | |||
| 8e282a3865 | |||
| dcbf76b233 | |||
| 70b11d953c | |||
| fa3b634c07 | |||
| ea86273a0e | |||
| 4f88e1f26d | |||
| 805e277429 | |||
| 3ce3de2963 | |||
| 3b5e9c74d6 | |||
| a9aaa36b2c | |||
| bef4ee1fbc | |||
| b3ddd084ba | |||
| fef3b7c647 | |||
| 4dfba31cae | |||
| 3004f29c08 | |||
| b994ce5b55 | |||
| 6356f9d0e5 | |||
| 597c6f3dbc | |||
| 41cffac80c | |||
| c4cb6c65a9 | |||
| 46081a3e52 | |||
| a5fd671b92 | |||
| 8319512c83 | |||
| c1db692982 | |||
| aec2bfd2a4 | |||
| 7bacf20f72 | |||
| 1479de19ef | |||
| bb9ca73db1 | |||
| 81bac8bca4 | |||
| 56d22292b0 | |||
| 9a11ff8ddb | |||
| a99b6d602d | |||
| 40921156b8 | |||
| bc3703140b | |||
| bd5b385909 | |||
| 0fe3db419e | |||
| e80bb480c4 | |||
| d4773212b7 | |||
| 9ebff9fd22 | |||
| 5d8edc0c8b | |||
| 78530b4e34 | |||
| 61f2823903 | |||
| 7446828866 | |||
| 0b37acec5b | |||
| 53ecf57f19 | |||
| e1c4365c10 | |||
| ebc60ac66c | |||
| 4004501d0f | |||
| a0265c3204 | |||
| 3ef84834fc | |||
| 3276949663 | |||
| 1ec69d6838 | |||
| 7f1063d09b | |||
| 883923de4a | |||
| 146981009b | |||
| 060b69293c | |||
| 3345c1e9dd | |||
| 1c8e2e34ba | |||
| 5ab51c07d1 | |||
| eee98e54d0 | |||
| b0340d5581 | |||
| 1124342eda | |||
| 329cb229f8 | |||
| bedb5eb6c5 | |||
| f184f8dab5 | |||
| 7ee0e8726e | |||
| a7347130de | |||
| f3c82ad837 | |||
| 1bde2b31f9 | |||
| 1edc617b55 | |||
| 2bb451d9e4 | |||
| 4588644d39 | |||
| ed94b4c46c | |||
| f96ddb4c10 | |||
| 1b0a65ecf2 | |||
| 33983c5402 | |||
| 8cfee9d693 | |||
| 64568b31d1 | |||
| 02c999725c | |||
| be11013ae2 | |||
| a84c4dc1f4 | |||
| d9455adc7f | |||
| b20aea7ab8 | |||
| 5e770dc8b0 | |||
| 137d5dfe90 | |||
| 655d11c1cc | |||
| e32987c408 | |||
| fa4e11c73b | |||
| e753d4d3a4 | |||
| 75d2c668d0 | |||
| 559082806b | |||
| 6f8d276545 | |||
| 582268f44f | |||
| 9b68674c4f | |||
| badae2ba9d | |||
| dd4f006b5f | |||
| c491c9e8fc | |||
| 094d736d38 | |||
| 22bfaf3c69 | |||
| 980e552eba | |||
| 4a141c3f57 | |||
| 59289bef6c | |||
| 0b02543ef2 | |||
| 3cef51ec4a | |||
| 6d86813647 | |||
| fb267acac3 | |||
| ba3e26f2b4 | |||
| 4f8d8de749 | |||
| 54c5bc5110 | |||
| c6675f82f0 | |||
| afe2c85047 | |||
| 671b11157e | |||
| 78fb55c35c | |||
| 559905da60 | |||
| e093c8aa72 | |||
| ba8a21142f | |||
| eca3625165 | |||
| 677e920dc8 | |||
| 38c0b24daa | |||
| 4e05502d7a | |||
| d0928a63bf | |||
| aa0bbd5aee | |||
| ce554dbdd0 | |||
| a0174e8666 | |||
| 8be419cfd6 | |||
| ca79bae36e | |||
| b1f0248fb3 | |||
| 77dd18466b | |||
| 5bb6e22679 | |||
| 9ea9291ab8 | |||
| 6ec73863ab | |||
| 8c2f93151d | |||
| 71ddc4ffc6 | |||
| 4909d693e3 | |||
| fe76bbe68a | |||
| d1f20822f1 | |||
| 1ed804db52 | |||
| 0e8b9bec2d | |||
| a3182c31cb | |||
| d2f2c76dfc | |||
| 2d1ae1b4c5 | |||
| 316409ecc3 | |||
| f0fc38bcb5 | |||
| e7a6b84107 | |||
| 02c3254961 | |||
| a90e1d7ccf | |||
| 6cdd64ac55 | |||
| aa1201ffb8 | |||
| 9b491c2f49 | |||
| be3e2ba521 | |||
| ccbb9e90ea | |||
| d07fe997a9 | |||
| b60996bcd1 | |||
| 272c0aad9c | |||
| 7566f10bb6 | |||
| 847b76b863 | |||
| 5c0ad030cc |
+27
-53
@@ -4,13 +4,16 @@ on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
|
||||
|
||||
jobs:
|
||||
spellcheck:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Install codespell
|
||||
shell: bash
|
||||
@@ -29,7 +32,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -68,7 +71,7 @@ jobs:
|
||||
ffversion: ${{ steps.ffversion.outputs.ffversion }}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -137,7 +140,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -198,7 +201,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -237,7 +240,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -273,7 +276,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -308,7 +311,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -343,7 +346,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -374,7 +377,7 @@ jobs:
|
||||
name: Musl-amd64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: setup alpine linux
|
||||
uses: jirutka/setup-alpine@master
|
||||
@@ -416,7 +419,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -463,7 +466,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -507,7 +510,7 @@ jobs:
|
||||
name: SunOS-amd64
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/omnios-vm@v1
|
||||
@@ -515,8 +518,9 @@ jobs:
|
||||
usesh: true
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg install pkg:/package/pkg
|
||||
pkg update --accept
|
||||
pkg install gcc13 cmake git pkg-config glib2 dbus sqlite-3 imagemagick
|
||||
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick
|
||||
|
||||
run: |
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
@@ -543,7 +547,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -580,7 +584,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -616,7 +620,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -628,7 +632,7 @@ jobs:
|
||||
version: '10.1'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick opencl-headers ocl-icd
|
||||
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -647,13 +651,12 @@ jobs:
|
||||
dragonfly-amd64:
|
||||
name: DragonFly-amd64
|
||||
runs-on: ubuntu-latest
|
||||
if: false
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/dragonflybsd-vm@v1
|
||||
@@ -688,35 +691,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Fixup VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
version: 'r1beta5'
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
sync_files: false
|
||||
shutdown_vm: false
|
||||
run: |
|
||||
mv '/home/runner/work' '/boot/home/work'
|
||||
ln -sf '/boot/home/work' '/home/runner/work'
|
||||
|
||||
- name: Sync files to VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
version: 'r1beta5'
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
sync_files: runner-to-vm
|
||||
shutdown_vm: false
|
||||
run: |
|
||||
chown -R $(id -u):$(id -g) $(pwd)
|
||||
ls -l
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -726,10 +701,9 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
sync_files: vm-to-runner
|
||||
run: |
|
||||
uname -a
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -755,7 +729,7 @@ jobs:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
@@ -817,7 +791,7 @@ jobs:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
|
||||
+165
@@ -1,3 +1,168 @@
|
||||
# 2.51.0
|
||||
|
||||
Changes:
|
||||
* Fastfetch now requires [yyjson 0.12](https://github.com/ibireme/yyjson/releases/tag/0.12.0) to build when using `-DENABLE_SYSTEM_YYJSON=ON`.
|
||||
* The Disk module no longer shows hyperlink mountpoints by default, which cause issues on some real consoles (Disk)
|
||||
* Instead, the custom key for the Disk module now supports `{mountpoint-link}` and `{name-link}` to show hyperlinks for mountpoints and names. For example, `{ "type": "disk", "key": "Disk ({mountpoint-link})" }` can be used to restore the old behavior.
|
||||
|
||||
Features:
|
||||
* Adds `succeeded` module condition to JSONC config. When set to `false`, the module will only run if the last module failed (#1908)
|
||||
* Useful for displaying fallback placeholders when a module fails. For example:
|
||||
```jsonc
|
||||
{
|
||||
"host",
|
||||
// If fastfetch fails to detect host info, display "DIY PC" instead
|
||||
{
|
||||
"type": "custom",
|
||||
"condition": {
|
||||
"succeeded": false
|
||||
},
|
||||
"key": "Host",
|
||||
"format": "DIY PC"
|
||||
}
|
||||
}
|
||||
```
|
||||
* By upgrading to yyjson 0.12, fastfetch now adds [JSON5](https://json5.org/) format support for configuration files (#1907)
|
||||
* [JSON5](https://json5.org/) is a superset of JSONC that allows unquoted keys, single quotes, multi-line strings, etc., and is fully compatible with JSONC and strict JSON.
|
||||
* To use JSON5, simply name your config file with a `.json5` extension. The `.jsonc` extension is still supported and used as the default extension for better IDE syntax highlighting support.
|
||||
* Fastfetch has been ported to [`GNU/Hurd`](https://www.gnu.org/software/hurd/) (#1895)
|
||||
* Thanks to the efforts of @yelninei!
|
||||
* Built-in logos now honor `logo.width` (#1905)
|
||||
* When its value is larger than the actual logo width, the logo will be padded with spaces to the right
|
||||
* Adds Trinity DE version detection (#1917, DE, Linux)
|
||||
* Adds formatted free and available disk size fields (#1929, Disk)
|
||||
* `{size-free}`: free size of the disk
|
||||
* `{size-available}`: available size of the disk
|
||||
* See [askubuntu.com](https://askubuntu.com/questions/249387/df-h-used-space-avail-free-space-is-less-than-the-total-size-of-home) for the difference between free and available size
|
||||
* Adds [x86_64 micro-architecture level](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels) detection (#1928, CPU)
|
||||
* Useful when installing software that requires or is optimized for specific CPU features. E.g., [CachyOS](https://wiki.cachyos.org/features/optimized_repos/)
|
||||
* Exposed via `{march}` in custom format
|
||||
* Adds [Aarch64 micro-architecture level](https://en.wikipedia.org/wiki/AArch64#Profiles) detection (CPU)
|
||||
* Supported on Linux (including Android), macOS and Windows
|
||||
* This is not fully accurate because there are many optional features across different levels, and not all levels are detectable.
|
||||
* Exposed via `{march}` in custom format.
|
||||
* Adds shepherd detection support (InitSystem, Linux)
|
||||
|
||||
Bugfixes:
|
||||
* Refines GPU detection logic to correctly handle virtual devices (#1920, GPU, Windows)
|
||||
* Fixes possible default route detection failure when the route table is very large (#1919, LocalIP, Linux)
|
||||
* Fastfetch now correctly parses `hwdata/pci.ids` files alongside `pciids/pci.ids` on FreeBSD when detecting GPU names (#1924, GPU, FreeBSD)
|
||||
* Fixes twin WM detection (#1917, WM, Linux)
|
||||
* Various fixes for Android support
|
||||
* Corrects WM name for Android (WM, Android)
|
||||
* Fixes battery temperature detection when running in ADB (Battery, Android)
|
||||
* Adds CPU and GPU temperature detection support (CPU, Android)
|
||||
|
||||
Logos:
|
||||
* Adds AerynOS
|
||||
|
||||
# 2.50.2
|
||||
|
||||
Bugfixes:
|
||||
* Fixes linglong package detection V2 (#1903, Packages, Linux)
|
||||
* Fixes building with `-DENABLE_SYSTEM_YYJSON=ON` (#1904)
|
||||
* Fixes `showMac` does not honor `defaultRouteOnly` (#1902, LocalIP, Linux)
|
||||
* Fixes failing to acquire default route on Linux in certain cases (#1902, LocalIP, Linux)
|
||||
|
||||
# 2.50.1
|
||||
|
||||
Bugfixes:
|
||||
* Fixes percentage bar not displaying correctly in certain cases
|
||||
* Fixes linglong package detection on Debian 13 (#1899, Packages, Linux)
|
||||
|
||||
# 2.50.0
|
||||
|
||||
Changes:
|
||||
* Keys in JSON configuration files are now case-sensitive, as stated in v2.49.0.
|
||||
* This is a breaking change, but it should not affect most users as long as your config file passes JSON schema validation.
|
||||
* All module config flags have been removed, as stated in v2.49.0.
|
||||
* To configure modules via the command line, use: `echo '{"modules": [{"type":"custom","format":"Hello Fastfetch!"}]}' | fastfetch -c -`.
|
||||
* The percent bar config `display.bar.*` options have been replaced with a more organized, nested object structure.
|
||||
* `display.bar.charElapsed` has been renamed to `display.bar.char.elapsed`.
|
||||
* `display.bar.charTotal` has been renamed to `display.bar.char.total`.
|
||||
* `display.bar.borderLeft` has been renamed to `display.bar.border.left`.
|
||||
* `display.bar.borderRight` has been renamed to `display.bar.border.right`.
|
||||
* The undocumented flag `--load-config` has been removed.
|
||||
* Use `--config` or `-c` instead.
|
||||
* Flashfetch, a simplified fastfetch variant that used a hardcoded module list with direct function calls to reduce startup overhead, has been changed to a version that aims to match neofetch's behavior as closely as possible, for demonstration purposes.
|
||||
* Flashfetch is intended to be built from source (like [st](https://st.suckless.org/)). We do not provide prebuilt binaries in distributions.
|
||||
|
||||
Features:
|
||||
* Added support for reading JSON config from stdin using `--config -` or `-c -`.
|
||||
* Added `display.bar.border.{leftElapsed,rightElapsed}` for using the border as part of the bar content. (#1875)
|
||||
* `display.bar.border: null` has been added as a shorthand to disable bar borders.
|
||||
* Added `display.bar.color.{elapsed,total,border}` to customize the color of the elapsed, total, and border sections of the percent bar.
|
||||
* `display.bar.color: null` has been added as a shorthand to disable bar colors.
|
||||
* Improved Bedrock Linux detection (#1881, OS / Disk, Linux)
|
||||
* Added the command flag `--gen-config-full`, which generates a JSON config file containing all optional module options.
|
||||
* Improved the default IP address display when `localip.showAllIPs` is not set (LocalIP)
|
||||
* For IPv4, the preferred source address (if detected) is shown.
|
||||
* For IPv6, the first GUA or ULA that is not deprecated or temporary is shown.
|
||||
* Added support for interface speed detection on SunOS (LocalIP, SunOS)
|
||||
* Added detection support for Xlibre (#1888, WM, Linux)
|
||||
* Improved the accuracy of color detection (Cursor, macOS)
|
||||
* Improved the proformance of `Nix` package manager detection on macOS by porting optimizations form Linux port (#1893, Packages, macOS)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed custom object inheriting a key from the previous custom object if the key is blank (#1477)
|
||||
* Fixed a possible segfault when parsing color strings in the JSON config (#1878)
|
||||
* Fixed GPU driver detection when DRM is used (GPU, FreeBSD)
|
||||
* Fixed default route detection on DragonFly BSD (LocalIP, DFBSD)
|
||||
* Fixed lliurex detection (#1882, OS, Linux)
|
||||
* Fixed compatibility with `-ffast-math` (#1894)
|
||||
* Fixed physical GPU sometimes being ignored (#1896, GPU, Windows)
|
||||
|
||||
Logos:
|
||||
* Added ObsidianOS (#1890)
|
||||
|
||||
# 2.49.0
|
||||
|
||||
Deprecation Notice:
|
||||
* In fastfetch v2, the JSONC configuration format has been introduced, while command line configuration flags are kept for compatibility. Although they have the same effects, they use two different code paths, and as the number of flags grows, the codebase is becoming increasingly difficult to maintain.
|
||||
* Removal of module config flags is planned for **v2.50.0**, which will also fix a long-standing issue #1477.
|
||||
* Removal of most other config flags is also planned for later versions.
|
||||
* Keys of JSON configuration files will be all case-sensitive. Currently they are inconsistent. Planned for **v2.50.0**.
|
||||
|
||||
Changes:
|
||||
* Due to more restrictive permissions in macOS Tahoe, SSID detection on macOS 26+ requires root privileges. `<redacted>` will be displayed otherwise.
|
||||
|
||||
Features:
|
||||
* Improve `nouveau` driver support for `--gpu-driver-specific` (GPU, Linux)
|
||||
* VRAM size detection
|
||||
* GPU temperature detection
|
||||
* Core count detection (when available)
|
||||
* Improve Scoop package manager detection (Packages, Windows)
|
||||
* Support [`scoop-global`](https://github.com/ScoopInstaller/Install?tab=readme-ov-file#advanced-installation)
|
||||
* Read Scoop's config file to find the installation path of Scoop
|
||||
* Improve ARM SoC detection (CPU, Android)
|
||||
* Make SoC detection more lenient. Higher chance to match at the cost of accuracy.
|
||||
* Add more Snapdragon SoC names
|
||||
* Support labwc WM version detection, used for XFCE4 on Wayland (WM, Linux)
|
||||
* Improve accuracy of GPU temperature detection for Intel dedicated GPUs on Windows (GPU, Windows)
|
||||
* Parse unicode escaped strings generated by qt5ct (#1864, Font, Linux)
|
||||
* Add `--{duration,percent,size,freq,temp}-space-before-unit [always|never]` options to add a space before the unit when printing duration, percent, size, frequency and temperature values
|
||||
* Add `--duration-abbreviation` to abbreviate duration values in custom format
|
||||
* For example: `1 day, 2 hours, 3 mins` will be displayed as `1d 2h 3m`
|
||||
* Add `--percent-width` to pad the percent value with spaces to a fixed width
|
||||
* For example: `--percent-width 3` will display ` 50%` instead of `50%`; useful for aligning percent values in custom format
|
||||
|
||||
Bugfixes:
|
||||
* Improve accuracy of Flatpak count detection (#1856, Packages, Linux)
|
||||
* Remove qi package manager support (#1858, Packages, Linux)
|
||||
* Fix LocalIP module on Windows (LocalIP, Windows)
|
||||
* Fix default route detection when multiple network interfaces are connected
|
||||
* Fix link speed calculation
|
||||
* Fix interface status when the interface is up but not connected (Wifi, Linux)
|
||||
* Fix variable names in custom format (#1861)
|
||||
* `full-path` to `path` (Editor)
|
||||
* `session` to `session-name` (Users)
|
||||
* `name` to `project-name` (Version)
|
||||
* Fix wrong /s assignment in custom format (#1871, DiskIO)
|
||||
|
||||
Logos:
|
||||
* Add `Aeon`
|
||||
* Remove `Evolinx`
|
||||
|
||||
# 2.48.1
|
||||
|
||||
Features:
|
||||
|
||||
+119
-25
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.48.1
|
||||
VERSION 2.51.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -32,6 +32,8 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")
|
||||
set(SunOS TRUE CACHE BOOL "..." FORCE)
|
||||
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Haiku")
|
||||
set(Haiku TRUE CACHE BOOL "..." FORCE)
|
||||
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU")
|
||||
set(GNU TRUE CACHE BOOL "..." FORCE)
|
||||
elseif(NOT APPLE AND NOT WIN32)
|
||||
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
|
||||
endif()
|
||||
@@ -56,30 +58,30 @@ include(CheckIncludeFile)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
|
||||
cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD" OFF)
|
||||
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD" OFF)
|
||||
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_XFCONF "Enable libxfconf-0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_SQLITE3 "Enable sqlite3" ON "LINUX OR FreeBSD OR APPLE OR OpenBSD OR NetBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_RPM "Enable rpm" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR WIN32 OR SunOS OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_XFCONF "Enable libxfconf-0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_SQLITE3 "Enable sqlite3" ON "LINUX OR FreeBSD OR APPLE OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_RPM "Enable rpm" ON "LINUX OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR WIN32 OR SunOS OR Haiku OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_CHAFA "Enable chafa" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF)
|
||||
cmake_dependent_option(ENABLE_ZLIB "Enable zlib" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF)
|
||||
cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR WIN32 OR SunOS OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR WIN32 OR SunOS OR Haiku OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku" OFF)
|
||||
cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
|
||||
cmake_dependent_option(ENABLE_LIBZFS "Enable libzfs" ON "LINUX OR FreeBSD OR SunOS" OFF)
|
||||
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD" OFF)
|
||||
@@ -351,10 +353,11 @@ file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
|
||||
#######################
|
||||
|
||||
set(LIBFASTFETCH_SRC
|
||||
src/common/percent.c
|
||||
src/common/commandoption.c
|
||||
src/common/duration.c
|
||||
src/common/font.c
|
||||
src/common/format.c
|
||||
src/common/frequency.c
|
||||
src/common/init.c
|
||||
src/common/jsonconfig.c
|
||||
src/common/library.c
|
||||
@@ -363,10 +366,13 @@ set(LIBFASTFETCH_SRC
|
||||
src/common/networking/networking_common.c
|
||||
src/common/option.c
|
||||
src/common/parsing.c
|
||||
src/common/percent.c
|
||||
src/common/printing.c
|
||||
src/common/properties.c
|
||||
src/common/settings.c
|
||||
src/common/size.c
|
||||
src/common/temps.c
|
||||
src/common/time.c
|
||||
src/detection/bluetoothradio/bluetoothradio.c
|
||||
src/detection/bootmgr/bootmgr.c
|
||||
src/detection/chassis/chassis.c
|
||||
@@ -471,7 +477,6 @@ set(LIBFASTFETCH_SRC
|
||||
src/modules/wmtheme/wmtheme.c
|
||||
src/modules/zpool/zpool.c
|
||||
src/options/display.c
|
||||
src/options/modules.c
|
||||
src/options/logo.c
|
||||
src/options/general.c
|
||||
src/util/edidHelper.c
|
||||
@@ -545,6 +550,7 @@ if(LINUX)
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_linux.c
|
||||
src/detection/packages/packages_linux.c
|
||||
src/detection/packages/packages_nix.c
|
||||
src/detection/poweradapter/poweradapter_linux.c
|
||||
src/detection/processes/processes_linux.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
@@ -593,7 +599,7 @@ elseif(ANDROID)
|
||||
src/detection/diskio/diskio_linux.c
|
||||
src/detection/displayserver/displayserver_android.c
|
||||
src/detection/font/font_nosupport.c
|
||||
src/detection/gpu/gpu_nosupport.c
|
||||
src/detection/gpu/gpu_android.c
|
||||
src/detection/host/host_android.c
|
||||
src/detection/icons/icons_nosupport.c
|
||||
src/detection/initsystem/initsystem_linux.c
|
||||
@@ -611,6 +617,7 @@ elseif(ANDROID)
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_android.c
|
||||
src/detection/packages/packages_linux.c
|
||||
src/detection/packages/packages_nix.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_linux.c
|
||||
src/detection/sound/sound_nosupport.c
|
||||
@@ -893,7 +900,7 @@ elseif(OpenBSD)
|
||||
elseif(APPLE)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/netif/netif_apple.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/common/sysctl.c
|
||||
@@ -937,6 +944,7 @@ elseif(APPLE)
|
||||
src/detection/opengl/opengl_apple.c
|
||||
src/detection/os/os_apple.m
|
||||
src/detection/packages/packages_apple.c
|
||||
src/detection/packages/packages_nix.c
|
||||
src/detection/poweradapter/poweradapter_apple.c
|
||||
src/detection/processes/processes_bsd.c
|
||||
src/detection/sound/sound_apple.c
|
||||
@@ -1039,7 +1047,7 @@ elseif(SunOS)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_bsd.c
|
||||
src/common/netif/netif_apple.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/detection/battery/battery_nosupport.c
|
||||
@@ -1186,6 +1194,84 @@ elseif(Haiku)
|
||||
src/util/binary_linux.c
|
||||
src/util/haiku/version.cpp
|
||||
)
|
||||
elseif(GNU)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_gnu.c
|
||||
src/common/networking/networking_linux.c
|
||||
src/common/processing_linux.c
|
||||
src/detection/battery/battery_nosupport.c
|
||||
src/detection/bios/bios_nosupport.c
|
||||
src/detection/board/board_nosupport.c
|
||||
src/detection/bootmgr/bootmgr_nosupport.c
|
||||
src/detection/brightness/brightness_nosupport.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_nosupport.c
|
||||
src/detection/cpu/cpu_linux.c
|
||||
src/detection/cpucache/cpucache_nosupport.c
|
||||
src/detection/cpuusage/cpuusage_linux.c
|
||||
src/detection/cursor/cursor_linux.c
|
||||
src/detection/bluetooth/bluetooth_linux.c
|
||||
src/detection/bluetoothradio/bluetoothradio_linux.c
|
||||
src/detection/disk/disk_linux.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_nosupport.c
|
||||
src/detection/physicalmemory/physicalmemory_nosupport.c
|
||||
src/detection/diskio/diskio_nosupport.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/drm.c
|
||||
src/detection/displayserver/linux/wayland/wayland.c
|
||||
src/detection/displayserver/linux/wayland/global-output.c
|
||||
src/detection/displayserver/linux/wayland/zwlr-output.c
|
||||
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
|
||||
src/detection/displayserver/linux/wmde.c
|
||||
src/detection/displayserver/linux/xcb.c
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_nosupport.c
|
||||
src/detection/gpu/gpu_pci.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_nosupport.c
|
||||
src/detection/icons/icons_linux.c
|
||||
src/detection/initsystem/initsystem_linux.c
|
||||
src/detection/keyboard/keyboard_nosupport.c
|
||||
src/detection/libc/libc_linux.c
|
||||
src/detection/lm/lm_linux.c
|
||||
src/detection/loadavg/loadavg_linux.c
|
||||
src/detection/locale/locale_linux.c
|
||||
src/detection/localip/localip_linux.c
|
||||
src/detection/gamepad/gamepad_nosupport.c
|
||||
src/detection/media/media_linux.c
|
||||
src/detection/memory/memory_linux.c
|
||||
src/detection/mouse/mouse_nosupport.c
|
||||
src/detection/netio/netio_nosupport.c
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_linux.c
|
||||
src/detection/packages/packages_linux.c
|
||||
src/detection/packages/packages_nix.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_linux.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
src/detection/sound/sound_linux.c
|
||||
src/detection/swap/swap_linux.c
|
||||
src/detection/terminalfont/terminalfont_linux.c
|
||||
src/detection/terminalshell/terminalshell_linux.c
|
||||
src/detection/terminalsize/terminalsize_linux.c
|
||||
src/detection/theme/theme_linux.c
|
||||
src/detection/tpm/tpm_nosupport.c
|
||||
src/detection/uptime/uptime_linux.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_nosupport.c
|
||||
src/detection/zpool/zpool_nosupport.c
|
||||
src/util/platform/FFPlatform_unix.c
|
||||
src/util/binary_linux.c
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENABLE_DIRECTX_HEADERS)
|
||||
@@ -1309,6 +1395,10 @@ elseif(NetBSD)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/usr/X11R7/lib -Wl,-rpath,/usr/pkg/lib") # ditto
|
||||
elseif(Haiku)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE)
|
||||
elseif(GNU)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE)
|
||||
# On Hurd PATH_MAX is not defined. Set an arbitrary limit as workaround.
|
||||
target_compile_definitions(libfastfetch PUBLIC PATH_MAX=4096)
|
||||
endif()
|
||||
|
||||
if(FreeBSD OR OpenBSD OR NetBSD)
|
||||
@@ -1633,6 +1723,10 @@ elseif(SunOS)
|
||||
PRIVATE "nvpair"
|
||||
PRIVATE "devinfo"
|
||||
)
|
||||
elseif(GNU)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "m"
|
||||
)
|
||||
elseif(ANDROID)
|
||||
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
|
||||
if(HAVE_LIBANDROID_WORDEXP_STATIC)
|
||||
|
||||
@@ -36,7 +36,6 @@ Some distributions package outdated versions of fastfetch. Older versions receiv
|
||||
<img src="https://repology.org/badge/vertical-allrepos/fastfetch.svg?columns=2" alt="Packaging status" align="right">
|
||||
</a>
|
||||
|
||||
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (for Ubuntu 22.04 or newer)
|
||||
* Debian: `apt install fastfetch` (for Debian 13 or newer)
|
||||
* Debian / Ubuntu: Download `fastfetch-linux-<proper architecture>.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and double-click it (for Ubuntu 20.04 or newer and Debian 11 or newer).
|
||||
* Arch Linux: `pacman -S fastfetch`
|
||||
@@ -58,7 +57,7 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
|
||||
|
||||
### macOS
|
||||
|
||||
* [HomeBrew](https://formulae.brew.sh/formula/fastfetch#default): `brew install fastfetch`
|
||||
* [Homebrew](https://formulae.brew.sh/formula/fastfetch#default): `brew install fastfetch`
|
||||
* [MacPorts](https://ports.macports.org/port/fastfetch/): `sudo port install fastfetch`
|
||||
|
||||
### Windows
|
||||
@@ -95,7 +94,8 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
|
||||
* Run with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) to find what interests you: `fastfetch -c all.jsonc`
|
||||
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
|
||||
* Display help messages: `fastfetch --help`
|
||||
* Generate a config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
|
||||
* Generate a minimal config file: `fastfetch [-s <module1>[:<module2>]] --gen-config [</path/to/config.jsonc>]`
|
||||
* Use: `--gen-config-full` to generate a full config file with all optional options
|
||||
|
||||
## Customization
|
||||
|
||||
|
||||
Vendored
+12
@@ -1,3 +1,15 @@
|
||||
fastfetch (2.50.2) jammy; urgency=medium
|
||||
|
||||
* Update to 2.50.2
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 21 Aug 2025 10:33:07 +0800
|
||||
|
||||
fastfetch (2.49.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.49.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 31 Jul 2025 14:32:59 +0800
|
||||
|
||||
fastfetch (2.48.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.48.0
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
fastfetch_2.48.0_source.buildinfo universe/utils optional
|
||||
fastfetch_2.50.2_source.buildinfo universe/utils optional
|
||||
|
||||
+581
-185
File diff suppressed because it is too large
Load Diff
@@ -12,10 +12,11 @@
|
||||
"type": ["bar", "hide-others"]
|
||||
},
|
||||
"bar": {
|
||||
"borderLeft": "",
|
||||
"borderRight": "",
|
||||
"charElapsed": "█",
|
||||
"charTotal": "░",
|
||||
"border": null,
|
||||
"char": {
|
||||
"elapsed": "█",
|
||||
"total": "░"
|
||||
},
|
||||
"width": 40
|
||||
},
|
||||
"constants": [
|
||||
|
||||
+85
-24
@@ -6,11 +6,13 @@
|
||||
"keys": "blue"
|
||||
},
|
||||
"separator": "",
|
||||
// Constants are reusable strings referenced by {$1}, {$2}, etc.
|
||||
// These contain ANSI escape codes for cursor positioning
|
||||
"constants": [
|
||||
"──────────────────────────────────────────────",
|
||||
"\u001b[47D",
|
||||
"\u001b[47C",
|
||||
"\u001b[46C"
|
||||
"──────────────────────────────────────────────", // {$1} - horizontal line for borders
|
||||
"\u001b[47D", // {$2} - move cursor left 47 columns
|
||||
"\u001b[47C", // {$3} - move cursor right 47 columns
|
||||
"\u001b[46C" // {$4} - move cursor right 46 columns
|
||||
],
|
||||
"brightColor": false
|
||||
},
|
||||
@@ -22,6 +24,24 @@
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
// Key format breakdown for OS module:
|
||||
// "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
|
||||
//
|
||||
// │ - Left border of key block
|
||||
// {icon} - OS icon (defined internally by fastfetch)
|
||||
// \u001b[s - ANSI escape: save cursor position (ESC[s)
|
||||
// {sysname} - Format variable: system name (e.g., "Linux", "Darwin")
|
||||
// \u001b[u - ANSI escape: restore cursor to saved position (ESC[u)
|
||||
// Necessary because the length of `{sysname}` differs between different platforms
|
||||
// \u001b[10C - ANSI escape: move cursor right 10 columns (ESC[10C)
|
||||
// │ - Right border of key block (always 10 columns from left border)
|
||||
// {$3} - Reference to constants[2]: move cursor right 47 columns
|
||||
// │ - Right border of value block
|
||||
// {$2} - Reference to constants[1]: move cursor left 47 columns
|
||||
//
|
||||
// This creates a fixed-width layout where the key block is exactly 10 columns wide,
|
||||
// regardless of the actual content length. The cursor manipulation ensures proper
|
||||
// alignment for the table-like structure.
|
||||
"key": "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
|
||||
},
|
||||
{
|
||||
@@ -34,7 +54,7 @@
|
||||
"key": "│ {icon} Locale │{$3}│{$2}"
|
||||
},
|
||||
|
||||
// Hardware
|
||||
// Hardware section with cyan color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#cyan}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
@@ -42,6 +62,11 @@
|
||||
},
|
||||
{
|
||||
"type": "chassis",
|
||||
// Similar structure but with cyan color formatting:
|
||||
// │{#cyan}│ - Left border with cyan color
|
||||
// {icon} - Chassis icon
|
||||
// Chassis - Fixed label text
|
||||
// │{$4}│{#keys}│{$2} - Positioning and borders for value area
|
||||
"key": "│{#cyan}│ {icon} Chassis │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
@@ -76,7 +101,7 @@
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Desktop
|
||||
// Desktop section with green color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#green}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
@@ -106,7 +131,7 @@
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Terminal
|
||||
// Terminal section with yellow color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#yellow}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
@@ -138,7 +163,7 @@
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Development
|
||||
// Development section with red color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#red}┌──────────────┬{$1}┐{#keys}│\u001b[39D",
|
||||
@@ -146,31 +171,44 @@
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"keyIcon": "", // Custom icon override
|
||||
"key": "│{#red}│ {icon} Rust │{$4}│{#keys}│{$2}",
|
||||
"text": "rustc --version | cut -d' ' -f2",
|
||||
"format": "rustc {}"
|
||||
"text": "rustc --version",
|
||||
"format": "rustc {~6,13}" // Print 6th to 13th characters (version number)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"condition": {
|
||||
"!system": "Windows" // Posix version
|
||||
},
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
|
||||
"text": "clang --version | head -1 | awk '{print $NF}'",
|
||||
"format": "clang {}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"condition": {
|
||||
"system": "Windows" // Windows version
|
||||
},
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
|
||||
"text": "clang --version | findstr version", // Finds the line with "version"
|
||||
"format": "clang {~-6}" // Prints the last 6 characters (version number)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} NodeJS │{$4}│{#keys}│{$2}",
|
||||
"text": "node --version",
|
||||
"format": "node {~1}"
|
||||
"format": "node {~1}" // {~1} removes first character (v)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Go │{$4}│{#keys}│{$2}",
|
||||
"text": "go version | cut -d' ' -f3",
|
||||
"format": "go {~2}"
|
||||
"format": "go {~2}" // {~2} removes first 2 characters (go)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
@@ -200,7 +238,7 @@
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Uptime
|
||||
// Uptime section with magenta color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#magenta}┌──────────────┬{$1}┐{#keys}│\u001b[36D",
|
||||
@@ -212,28 +250,28 @@
|
||||
},
|
||||
{
|
||||
"type": "users",
|
||||
"myselfOnly": true,
|
||||
"myselfOnly": true, // Only show current user
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"condition": { // Conditional module: only show on non-macOS
|
||||
"!system": "macOS"
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"folders": "/",
|
||||
"format": "{create-time:10} [{days} days]"
|
||||
"folders": "/", // Check root filesystem
|
||||
"format": "{create-time:10} [{days} days]" // Show creation time and age in days
|
||||
},
|
||||
{
|
||||
"condition": {
|
||||
"condition": { // Conditional module: only show on macOS
|
||||
"system": "macOS"
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"folders": "/System/Volumes/VM",
|
||||
"folders": "/System/Volumes/VM", // Work around for APFS on macOS
|
||||
"format": "{create-time:10} [{days} days]"
|
||||
},
|
||||
{
|
||||
@@ -243,12 +281,35 @@
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "└─────────────────{$1}┘",
|
||||
"key": "└─────────────────{$1}┘", // Bottom border of the entire layout
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// End
|
||||
"break",
|
||||
"colors"
|
||||
// End with color palette and line break
|
||||
"break", // Add a blank line
|
||||
"colors" // Display color palette
|
||||
]
|
||||
}
|
||||
|
||||
/*
|
||||
Key Format Structure Explanation:
|
||||
|
||||
The key format uses a combination of:
|
||||
1. Unicode box drawing characters (│ ┌ ┐ └ ┘ ┬ ┴) for borders
|
||||
2. ANSI escape codes for cursor positioning (\u001b[...)
|
||||
3. Format variables ({icon}, {sysname}, etc.)
|
||||
4. Constant references ({$1}, {$2}, etc.)
|
||||
5. Color formatting ({#color})
|
||||
|
||||
ANSI Escape Codes Used:
|
||||
- \u001b[s - Save cursor position (ESC[s)
|
||||
- \u001b[u - Restore cursor position (ESC[u)
|
||||
- \u001b[nC - Move cursor right n columns (ESC[nC)
|
||||
- \u001b[nD - Move cursor left n columns (ESC[nD)
|
||||
|
||||
This creates a table-like layout with fixed column widths and proper alignment,
|
||||
regardless of the actual content length in each field.
|
||||
|
||||
For more ANSI escape code reference, see:
|
||||
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#cursor-controls
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"type": "small"
|
||||
},
|
||||
"display": {
|
||||
"separator": " ",
|
||||
"key": {
|
||||
"type": "both"
|
||||
},
|
||||
"bar": {
|
||||
"border": {
|
||||
"left": "\uee00",
|
||||
"leftElapsed": "\uee03",
|
||||
"right": "\uee02",
|
||||
"rightElapsed": "\uee05"
|
||||
},
|
||||
"char": {
|
||||
"total": "\uee01",
|
||||
"elapsed": "\uee04"
|
||||
},
|
||||
"color": {
|
||||
"total": null
|
||||
}
|
||||
},
|
||||
"percent": {
|
||||
"type": [
|
||||
"bar",
|
||||
"bar-monochrome"
|
||||
]
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"title",
|
||||
"separator",
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "MEM"
|
||||
},
|
||||
{
|
||||
"type": "swap",
|
||||
"key": "SWP"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "DSK"
|
||||
},
|
||||
{
|
||||
"type": "battery",
|
||||
"key": "BAT"
|
||||
},
|
||||
{
|
||||
"type": "brightness",
|
||||
"key": "BGT"
|
||||
},
|
||||
{
|
||||
"type": "colors",
|
||||
"paddingLeft": 6,
|
||||
"symbol": "circle"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// #1887
|
||||
{
|
||||
"$schema": "file:///Users/carter/fastfetch/doc/json_schema.json",
|
||||
"logo": null,
|
||||
"display": {
|
||||
"constants": [
|
||||
"\u001b[s\u001b[33C│\u001b[u",
|
||||
" » "
|
||||
],
|
||||
"separator": "",
|
||||
"percent": {
|
||||
"type": ["num", "bar"]
|
||||
},
|
||||
"brightColor": false,
|
||||
"bar": {
|
||||
"border": {
|
||||
"left": "[",
|
||||
"leftElapsed": "[",
|
||||
"right": "]",
|
||||
"rightElapsed": "]"
|
||||
},
|
||||
"char": {
|
||||
"elapsed": "─",
|
||||
"total": "─"
|
||||
},
|
||||
"color": {
|
||||
"elapsed": "default",
|
||||
"total": "light_black"
|
||||
},
|
||||
"width": 16
|
||||
},
|
||||
"color": {
|
||||
"separator": "default",
|
||||
"keys": "default",
|
||||
"output": "default"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"title",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}OS{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "│ {$1}",
|
||||
"format": "{size-percentage-bar} {size-percentage}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "│ {$1}",
|
||||
"format": "{size-used} / {size-total}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}UI{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "wmtheme",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "display",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{width}x{height} @ {refresh-rate} Hz"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}HW{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "cpu",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{percentage-bar} {percentage}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│ {$1}",
|
||||
"format": "{used} / {total}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -8,8 +8,10 @@
|
||||
"width": 11
|
||||
},
|
||||
"bar": {
|
||||
"charElapsed": "=",
|
||||
"charTotal": "-",
|
||||
"char": {
|
||||
"elapsed": "=",
|
||||
"total": "-"
|
||||
},
|
||||
"width": 13
|
||||
},
|
||||
"percent": {
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
"display": {
|
||||
"size": {
|
||||
"maxPrefix": "MB",
|
||||
"ndigits": 0
|
||||
"ndigits": 0,
|
||||
"spaceBeforeUnit": "never"
|
||||
},
|
||||
"freq": {
|
||||
"ndigits": 3,
|
||||
"spaceBeforeUnit": "never"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
@@ -39,11 +44,12 @@
|
||||
"cpu",
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "GPU"
|
||||
"key": "GPU",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"format": "{} / {}"
|
||||
"format": "{used} / {total}"
|
||||
},
|
||||
"break",
|
||||
"colors"
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/ibireme/yyjson",
|
||||
"license": "MIT ( embed in source )",
|
||||
"version": "0.11.1",
|
||||
"version": "0.12.0",
|
||||
"author": "ibireme"
|
||||
}
|
||||
|
||||
Vendored
+4196
-3943
File diff suppressed because it is too large
Load Diff
Vendored
+174
-116
@@ -32,7 +32,7 @@
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Header Files
|
||||
* MARK: - Header Files
|
||||
*============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Compile-time Options
|
||||
* MARK: - Compile-time Options
|
||||
*============================================================================*/
|
||||
|
||||
/*
|
||||
@@ -89,14 +89,8 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
Define as 1 to disable non-standard JSON features support at compile-time:
|
||||
- YYJSON_READ_ALLOW_INF_AND_NAN
|
||||
- YYJSON_READ_ALLOW_COMMENTS
|
||||
- YYJSON_READ_ALLOW_TRAILING_COMMAS
|
||||
- YYJSON_READ_ALLOW_INVALID_UNICODE
|
||||
- YYJSON_READ_ALLOW_BOM
|
||||
- YYJSON_WRITE_ALLOW_INF_AND_NAN
|
||||
- YYJSON_WRITE_ALLOW_INVALID_UNICODE
|
||||
Define as 1 to disable non-standard JSON features support at compile-time,
|
||||
such as YYJSON_READ_ALLOW_XXX and YYJSON_WRITE_ALLOW_XXX.
|
||||
|
||||
This reduces binary size by about 10%, and slightly improves performance.
|
||||
*/
|
||||
@@ -151,7 +145,7 @@
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Compiler Macros
|
||||
* MARK: - Compiler Macros
|
||||
*============================================================================*/
|
||||
|
||||
/** compiler version (MSVC) */
|
||||
@@ -179,8 +173,10 @@
|
||||
#endif
|
||||
|
||||
/** real gcc check */
|
||||
#if !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__ICC) && \
|
||||
defined(__GNUC__)
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
|
||||
!defined(__clang__) && !defined(__llvm__) && \
|
||||
!defined(__INTEL_COMPILER) && !defined(__ICC) && \
|
||||
!defined(__NVCC__) && !defined(__PGI) && !defined(__TINYC__)
|
||||
# define YYJSON_IS_REAL_GCC 1
|
||||
#else
|
||||
# define YYJSON_IS_REAL_GCC 0
|
||||
@@ -465,7 +461,7 @@
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Compile Hint Begin
|
||||
* MARK: - Compile Hint Begin
|
||||
*============================================================================*/
|
||||
|
||||
/* extern "C" begin */
|
||||
@@ -492,23 +488,23 @@ extern "C" {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Version
|
||||
* MARK: - Version
|
||||
*============================================================================*/
|
||||
|
||||
/** The major version of yyjson. */
|
||||
#define YYJSON_VERSION_MAJOR 0
|
||||
|
||||
/** The minor version of yyjson. */
|
||||
#define YYJSON_VERSION_MINOR 11
|
||||
#define YYJSON_VERSION_MINOR 12
|
||||
|
||||
/** The patch version of yyjson. */
|
||||
#define YYJSON_VERSION_PATCH 1
|
||||
#define YYJSON_VERSION_PATCH 0
|
||||
|
||||
/** The version of yyjson in hex: `(major << 16) | (minor << 8) | (patch)`. */
|
||||
#define YYJSON_VERSION_HEX 0x000B01
|
||||
#define YYJSON_VERSION_HEX 0x000C00
|
||||
|
||||
/** The version string of yyjson. */
|
||||
#define YYJSON_VERSION_STRING "0.11.1"
|
||||
#define YYJSON_VERSION_STRING "0.12.0"
|
||||
|
||||
/** The version of yyjson in hex, same as `YYJSON_VERSION_HEX`. */
|
||||
yyjson_api uint32_t yyjson_version(void);
|
||||
@@ -516,7 +512,7 @@ yyjson_api uint32_t yyjson_version(void);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Types
|
||||
* MARK: - JSON Types
|
||||
*============================================================================*/
|
||||
|
||||
/** Type of a JSON value (3 bit). */
|
||||
@@ -578,7 +574,7 @@ typedef uint8_t yyjson_subtype;
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Allocator
|
||||
* MARK: - Allocator
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -662,7 +658,7 @@ yyjson_api void yyjson_alc_dyn_free(yyjson_alc *alc);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Text Locating
|
||||
* MARK: - Text Locating
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -686,7 +682,7 @@ yyjson_api bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Structure
|
||||
* MARK: - JSON Structure
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -720,7 +716,7 @@ typedef struct yyjson_mut_val yyjson_mut_val;
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Reader API
|
||||
* MARK: - JSON Reader API
|
||||
*============================================================================*/
|
||||
|
||||
/** Run-time options for JSON reader. */
|
||||
@@ -734,7 +730,7 @@ typedef uint32_t yyjson_read_flag;
|
||||
- Report error if double number is infinity.
|
||||
- Report error if string contains invalid UTF-8 character or BOM.
|
||||
- Report error on trailing commas, comments, inf and nan literals. */
|
||||
static const yyjson_read_flag YYJSON_READ_NOFLAG = 0;
|
||||
static const yyjson_read_flag YYJSON_READ_NOFLAG = 0;
|
||||
|
||||
/** Read the input data in-situ.
|
||||
This option allows the reader to modify and use input data to store string
|
||||
@@ -742,27 +738,27 @@ static const yyjson_read_flag YYJSON_READ_NOFLAG = 0;
|
||||
The caller should hold the input data before free the document.
|
||||
The input data must be padded by at least `YYJSON_PADDING_SIZE` bytes.
|
||||
For example: `[1,2]` should be `[1,2]\0\0\0\0`, input length should be 5. */
|
||||
static const yyjson_read_flag YYJSON_READ_INSITU = 1 << 0;
|
||||
static const yyjson_read_flag YYJSON_READ_INSITU = 1 << 0;
|
||||
|
||||
/** Stop when done instead of issuing an error if there's additional content
|
||||
after a JSON document. This option may be used to parse small pieces of JSON
|
||||
in larger data, such as `NDJSON`. */
|
||||
static const yyjson_read_flag YYJSON_READ_STOP_WHEN_DONE = 1 << 1;
|
||||
static const yyjson_read_flag YYJSON_READ_STOP_WHEN_DONE = 1 << 1;
|
||||
|
||||
/** Allow single trailing comma at the end of an object or array,
|
||||
such as `[1,2,3,]`, `{"a":1,"b":2,}` (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_TRAILING_COMMAS = 1 << 2;
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_TRAILING_COMMAS = 1 << 2;
|
||||
|
||||
/** Allow C-style single line and multiple line comments (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_COMMENTS = 1 << 3;
|
||||
/** Allow C-style single-line and mult-line comments (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_COMMENTS = 1 << 3;
|
||||
|
||||
/** Allow inf/nan number and literal, case-insensitive,
|
||||
such as 1e999, NaN, inf, -Infinity (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_INF_AND_NAN = 1 << 4;
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_INF_AND_NAN = 1 << 4;
|
||||
|
||||
/** Read all numbers as raw strings (value with `YYJSON_TYPE_RAW` type),
|
||||
inf/nan literal is also read as raw with `ALLOW_INF_AND_NAN` flag. */
|
||||
static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW = 1 << 5;
|
||||
static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW = 1 << 5;
|
||||
|
||||
/** Allow reading invalid unicode when parsing string values (non-standard).
|
||||
Invalid characters will be allowed to appear in the string values, but
|
||||
@@ -772,16 +768,62 @@ static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW = 1 << 5;
|
||||
@warning Strings in JSON values may contain incorrect encoding when this
|
||||
option is used, you need to handle these strings carefully to avoid security
|
||||
risks. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_INVALID_UNICODE = 1 << 6;
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_INVALID_UNICODE = 1 << 6;
|
||||
|
||||
/** Read big numbers as raw strings. These big numbers include integers that
|
||||
cannot be represented by `int64_t` and `uint64_t`, and floating-point
|
||||
numbers that cannot be represented by finite `double`.
|
||||
The flag will be overridden by `YYJSON_READ_NUMBER_AS_RAW` flag. */
|
||||
static const yyjson_read_flag YYJSON_READ_BIGNUM_AS_RAW = 1 << 7;
|
||||
static const yyjson_read_flag YYJSON_READ_BIGNUM_AS_RAW = 1 << 7;
|
||||
|
||||
/** Allow UTF-8 BOM and skip it before parsing if any (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_BOM = 1 << 8;
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_BOM = 1 << 8;
|
||||
|
||||
/** Allow extended number formats (non-standard):
|
||||
- Hexadecimal numbers, such as `0x7B`.
|
||||
- Numbers with leading or trailing decimal point, such as `.123`, `123.`.
|
||||
- Numbers with a leading plus sign, such as `+123`. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_NUMBER = 1 << 9;
|
||||
|
||||
/** Allow extended escape sequences in strings (non-standard):
|
||||
- Additional escapes: `\a`, `\e`, `\v`, ``\'``, `\?`, `\0`.
|
||||
- Hex escapes: `\xNN`, such as `\x7B`.
|
||||
- Line continuation: backslash followed by line terminator sequences.
|
||||
- Unknown escape: if backslash is followed by an unsupported character,
|
||||
the backslash will be removed and the character will be kept as-is.
|
||||
However, `\1`-`\9` will still trigger an error. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_ESCAPE = 1 << 10;
|
||||
|
||||
/** Allow extended whitespace characters (non-standard):
|
||||
- Vertical tab `\v` and form feed `\f`.
|
||||
- Line separator `\u2028` and paragraph separator `\u2029`.
|
||||
- Non-breaking space `\xA0`.
|
||||
- Byte order mark: `\uFEFF`.
|
||||
- Other Unicode characters in the Zs (Separator, space) category. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_WHITESPACE = 1 << 11;
|
||||
|
||||
/** Allow strings enclosed in single quotes (non-standard), such as ``'ab'``. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_SINGLE_QUOTED_STR = 1 << 12;
|
||||
|
||||
/** Allow object keys without quotes (non-standard), such as `{a:1,b:2}`.
|
||||
This extends the ECMAScript IdentifierName rule by allowing any
|
||||
non-whitespace character with code point above `U+007F`. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_UNQUOTED_KEY = 1 << 13;
|
||||
|
||||
/** Allow JSON5 format, see: [https://json5.org].
|
||||
This flag supports all JSON5 features with some additional extensions:
|
||||
- Accepts more escape sequences than JSON5 (e.g. `\a`, `\e`).
|
||||
- Unquoted keys are not limited to ECMAScript IdentifierName.
|
||||
- Allow case-insensitive `NaN`, `Inf` and `Infinity` literals. */
|
||||
static const yyjson_read_flag YYJSON_READ_JSON5 =
|
||||
(1 << 2) | /* YYJSON_READ_ALLOW_TRAILING_COMMAS */
|
||||
(1 << 3) | /* YYJSON_READ_ALLOW_COMMENTS */
|
||||
(1 << 4) | /* YYJSON_READ_ALLOW_INF_AND_NAN */
|
||||
(1 << 9) | /* YYJSON_READ_ALLOW_EXT_NUMBER */
|
||||
(1 << 10) | /* YYJSON_READ_ALLOW_EXT_ESCAPE */
|
||||
(1 << 11) | /* YYJSON_READ_ALLOW_EXT_WHITESPACE */
|
||||
(1 << 12) | /* YYJSON_READ_ALLOW_SINGLE_QUOTED_STR */
|
||||
(1 << 13); /* YYJSON_READ_ALLOW_UNQUOTED_KEY */
|
||||
|
||||
|
||||
|
||||
@@ -794,7 +836,7 @@ static const yyjson_read_code YYJSON_READ_SUCCESS = 0;
|
||||
/** Invalid parameter, such as NULL input string or 0 input length. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_PARAMETER = 1;
|
||||
|
||||
/** Memory allocation failure occurs. */
|
||||
/** Memory allocation failed. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_MEMORY_ALLOCATION = 2;
|
||||
|
||||
/** Input JSON string is empty. */
|
||||
@@ -803,7 +845,7 @@ static const yyjson_read_code YYJSON_READ_ERROR_EMPTY_CONTENT = 3;
|
||||
/** Unexpected content after document, such as `[123]abc`. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CONTENT = 4;
|
||||
|
||||
/** Unexpected ending, such as `[123`. */
|
||||
/** Unexpected end of input, the parsed part is valid, such as `[123`. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_END = 5;
|
||||
|
||||
/** Unexpected character inside the document, such as `[abc]`. */
|
||||
@@ -812,7 +854,7 @@ static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CHARACTER = 6;
|
||||
/** Invalid JSON structure, such as `[1,]`. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_JSON_STRUCTURE = 7;
|
||||
|
||||
/** Invalid comment, such as unclosed multi-line comment. */
|
||||
/** Invalid comment, deprecated, use `UNEXPECTED_END` for unclosed comment. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_COMMENT = 8;
|
||||
|
||||
/** Invalid number, such as `123.e12`, `000`. */
|
||||
@@ -830,7 +872,7 @@ static const yyjson_read_code YYJSON_READ_ERROR_FILE_OPEN = 12;
|
||||
/** Failed to read a file. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_FILE_READ = 13;
|
||||
|
||||
/** Unexpected ending during incremental parsing. Parsing state is saved. */
|
||||
/** Incomplete input during incremental parsing; parsing state is preserved. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_MORE = 14;
|
||||
|
||||
/** Error information for JSON reader. */
|
||||
@@ -884,6 +926,7 @@ yyjson_api yyjson_doc *yyjson_read_opts(char *dat,
|
||||
2. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return NULL.
|
||||
@param flg The JSON read options.
|
||||
Multiple options can be combined with `|` operator. 0 means no options.
|
||||
@@ -960,6 +1003,9 @@ typedef struct yyjson_incr_state yyjson_incr_state;
|
||||
2. Call `yyjson_incr_read()` repeatedly.
|
||||
3. Call `yyjson_incr_free()` to free the state.
|
||||
|
||||
Note: The incremental JSON reader only supports standard JSON.
|
||||
Flags for non-standard features (e.g. comments, trailing commas) are ignored.
|
||||
|
||||
@param buf The JSON data, null-terminator is not required.
|
||||
If this parameter is NULL, the function will fail and return NULL.
|
||||
@param buf_len The length of the JSON data in `buf`.
|
||||
@@ -1088,27 +1134,7 @@ yyjson_api const char *yyjson_read_number(const char *dat,
|
||||
const yyjson_alc *alc,
|
||||
yyjson_read_err *err);
|
||||
|
||||
/**
|
||||
Read a JSON number.
|
||||
|
||||
This function is thread-safe when data is not modified by other threads.
|
||||
|
||||
@param dat The JSON data (UTF-8 without BOM), null-terminator is required.
|
||||
If this parameter is NULL, the function will fail and return NULL.
|
||||
@param val The output value where result is stored.
|
||||
If this parameter is NULL, the function will fail and return NULL.
|
||||
The value will hold either UINT or SINT or REAL number;
|
||||
@param flg The JSON read options.
|
||||
Multiple options can be combined with `|` operator. 0 means no options.
|
||||
Supports `YYJSON_READ_NUMBER_AS_RAW` and `YYJSON_READ_ALLOW_INF_AND_NAN`.
|
||||
@param alc The memory allocator used for long number.
|
||||
It is only used when the built-in floating point reader is disabled.
|
||||
Pass NULL to use the libc's default allocator.
|
||||
@param err A pointer to receive error information.
|
||||
Pass NULL if you don't need error information.
|
||||
@return If successful, a pointer to the character after the last character
|
||||
used in the conversion, NULL if an error occurs.
|
||||
*/
|
||||
/** Same as `yyjson_read_number()`. */
|
||||
yyjson_api_inline const char *yyjson_mut_read_number(const char *dat,
|
||||
yyjson_mut_val *val,
|
||||
yyjson_read_flag flg,
|
||||
@@ -1122,7 +1148,7 @@ yyjson_api_inline const char *yyjson_mut_read_number(const char *dat,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Writer API
|
||||
* MARK: - JSON Writer API
|
||||
*============================================================================*/
|
||||
|
||||
/** Run-time options for JSON writer. */
|
||||
@@ -1230,7 +1256,7 @@ typedef struct yyjson_write_err {
|
||||
#if !defined(YYJSON_DISABLE_WRITER) || !YYJSON_DISABLE_WRITER
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Document Writer API
|
||||
* MARK: - JSON Document Writer API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -1267,6 +1293,7 @@ yyjson_api char *yyjson_write_opts(const yyjson_doc *doc,
|
||||
2. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return false.
|
||||
If this file is not empty, the content will be discarded.
|
||||
@param doc The JSON document.
|
||||
@@ -1370,6 +1397,7 @@ yyjson_api char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
|
||||
3. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return false.
|
||||
If this file is not empty, the content will be discarded.
|
||||
@param doc The mutable JSON document.
|
||||
@@ -1439,7 +1467,7 @@ yyjson_api_inline char *yyjson_mut_write(const yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Writer API
|
||||
* MARK: - JSON Value Writer API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -1476,6 +1504,7 @@ yyjson_api char *yyjson_val_write_opts(const yyjson_val *val,
|
||||
2. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return false.
|
||||
If this file is not empty, the content will be discarded.
|
||||
@param val The JSON root value.
|
||||
@@ -1577,6 +1606,7 @@ yyjson_api char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
|
||||
3. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return false.
|
||||
If this file is not empty, the content will be discarded.
|
||||
@param val The mutable JSON root value.
|
||||
@@ -1643,12 +1673,40 @@ yyjson_api_inline char *yyjson_mut_val_write(const yyjson_mut_val *val,
|
||||
return yyjson_mut_val_write_opts(val, flg, NULL, len, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
Write a JSON number.
|
||||
|
||||
@param val A JSON number value to be converted to a string.
|
||||
If this parameter is invalid, the function will fail and return NULL.
|
||||
@param buf A buffer to store the resulting null-terminated string.
|
||||
If this parameter is NULL, the function will fail and return NULL.
|
||||
For integer values, the buffer must be at least 21 bytes.
|
||||
For floating-point values, the buffer must be at least 40 bytes.
|
||||
@return On success, returns a pointer to the character after the last
|
||||
written character. On failure, returns NULL.
|
||||
@note
|
||||
- This function is thread-safe and does not allocate memory
|
||||
(when `YYJSON_DISABLE_FAST_FP_CONV` is not defined).
|
||||
- This function will fail and return NULL only in the following cases:
|
||||
1) `val` or `buf` is NULL;
|
||||
2) `val` is not a number type;
|
||||
3) `val` is `inf` or `nan`, and non-standard JSON is explicitly disabled
|
||||
via the `YYJSON_DISABLE_NON_STANDARD` flag.
|
||||
*/
|
||||
yyjson_api char *yyjson_write_number(const yyjson_val *val, char *buf);
|
||||
|
||||
/** Same as `yyjson_write_number()`. */
|
||||
yyjson_api_inline char *yyjson_mut_write_number(const yyjson_mut_val *val,
|
||||
char *buf) {
|
||||
return yyjson_write_number((const yyjson_val *)val, buf);
|
||||
}
|
||||
|
||||
#endif /* YYJSON_DISABLE_WRITER */
|
||||
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Document API
|
||||
* MARK: - JSON Document API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the root value of this JSON document.
|
||||
@@ -1673,7 +1731,7 @@ yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Type API
|
||||
* MARK: - JSON Value Type API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns whether the JSON value is raw.
|
||||
@@ -1735,7 +1793,7 @@ yyjson_api_inline bool yyjson_is_ctn(yyjson_val *val);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Content API
|
||||
* MARK: - JSON Value Content API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the JSON value's type.
|
||||
@@ -1760,7 +1818,7 @@ yyjson_api_inline const char *yyjson_get_type_desc(yyjson_val *val);
|
||||
yyjson_api_inline const char *yyjson_get_raw(yyjson_val *val);
|
||||
|
||||
/** Returns the content if the value is bool.
|
||||
Returns NULL if `val` is NULL or type is not bool. */
|
||||
Returns false if `val` is NULL or type is not bool. */
|
||||
yyjson_api_inline bool yyjson_get_bool(yyjson_val *val);
|
||||
|
||||
/** Returns the content and cast to uint64_t.
|
||||
@@ -1888,7 +1946,7 @@ yyjson_api_inline bool yyjson_set_str_noesc(yyjson_val *val, bool noesc);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Array API
|
||||
* MARK: - JSON Array API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the number of elements in this array.
|
||||
@@ -1914,7 +1972,7 @@ yyjson_api_inline yyjson_val *yyjson_arr_get_last(yyjson_val *arr);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Array Iterator API
|
||||
* MARK: - JSON Array Iterator API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -1996,7 +2054,7 @@ yyjson_api_inline yyjson_val *yyjson_arr_iter_next(yyjson_arr_iter *iter);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Object API
|
||||
* MARK: - JSON Object API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the number of key-value pairs in this object.
|
||||
@@ -2026,7 +2084,7 @@ yyjson_api_inline yyjson_val *yyjson_obj_getn(yyjson_val *obj, const char *key,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Object Iterator API
|
||||
* MARK: - JSON Object Iterator API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -2169,7 +2227,7 @@ yyjson_api_inline yyjson_val *yyjson_obj_iter_getn(yyjson_obj_iter *iter,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Document API
|
||||
* MARK: - Mutable JSON Document API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the root value of this JSON document.
|
||||
@@ -2273,7 +2331,7 @@ yyjson_api yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *val,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Type API
|
||||
* MARK: - Mutable JSON Value Type API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns whether the JSON value is raw.
|
||||
@@ -2335,7 +2393,7 @@ yyjson_api_inline bool yyjson_mut_is_ctn(yyjson_mut_val *val);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Content API
|
||||
* MARK: - Mutable JSON Value Content API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the JSON value's type.
|
||||
@@ -2504,7 +2562,7 @@ yyjson_api_inline bool yyjson_mut_set_obj(yyjson_mut_val *val);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Creation API
|
||||
* MARK: - Mutable JSON Value Creation API
|
||||
*============================================================================*/
|
||||
|
||||
/** Creates and returns a raw value, returns NULL on error.
|
||||
@@ -2605,7 +2663,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_strncpy(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array API
|
||||
* MARK: - Mutable JSON Array API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the number of elements in this array.
|
||||
@@ -2629,7 +2687,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_last(yyjson_mut_val *arr);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Iterator API
|
||||
* MARK: - Mutable JSON Array Iterator API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -2731,7 +2789,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_remove(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Creation API
|
||||
* MARK: - Mutable JSON Array Creation API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3092,7 +3150,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strncpy(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Modification API
|
||||
* MARK: - Mutable JSON Array Modification API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3205,7 +3263,7 @@ yyjson_api_inline bool yyjson_mut_arr_rotate(yyjson_mut_val *arr,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Modification Convenience API
|
||||
* MARK: - Mutable JSON Array Modification Convenience API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3411,7 +3469,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_obj(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object API
|
||||
* MARK: - Mutable JSON Object API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the number of key-value pairs in this object.
|
||||
@@ -3443,7 +3501,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_getn(yyjson_mut_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Iterator API
|
||||
* MARK: - Mutable JSON Object Iterator API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3605,7 +3663,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_getn(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Creation API
|
||||
* MARK: - Mutable JSON Object Creation API
|
||||
*============================================================================*/
|
||||
|
||||
/** Creates and returns a mutable object, returns NULL on error. */
|
||||
@@ -3652,7 +3710,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_kv(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Modification API
|
||||
* MARK: - Mutable JSON Object Modification API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3762,7 +3820,7 @@ yyjson_api_inline bool yyjson_mut_obj_rotate(yyjson_mut_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Modification Convenience API
|
||||
* MARK: - Mutable JSON Object Modification Convenience API
|
||||
*============================================================================*/
|
||||
|
||||
/** Adds a `null` value at the end of the object.
|
||||
@@ -4002,7 +4060,7 @@ yyjson_api_inline bool yyjson_mut_obj_rename_keyn(yyjson_mut_doc *doc,
|
||||
#if !defined(YYJSON_DISABLE_UTILS) || !YYJSON_DISABLE_UTILS
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Pointer API (RFC 6901)
|
||||
* MARK: - JSON Pointer API (RFC 6901)
|
||||
* https://tools.ietf.org/html/rfc6901
|
||||
*============================================================================*/
|
||||
|
||||
@@ -4587,7 +4645,7 @@ yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Patch API (RFC 6902)
|
||||
* MARK: - JSON Patch API (RFC 6902)
|
||||
* https://tools.ietf.org/html/rfc6902
|
||||
*============================================================================*/
|
||||
|
||||
@@ -4655,7 +4713,7 @@ yyjson_api yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Merge-Patch API (RFC 7386)
|
||||
* MARK: - JSON Merge-Patch API (RFC 7386)
|
||||
* https://tools.ietf.org/html/rfc7386
|
||||
*============================================================================*/
|
||||
|
||||
@@ -4688,7 +4746,7 @@ yyjson_api yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Structure (Implementation)
|
||||
* MARK: - JSON Structure (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
/** Payload of a JSON value (8 bytes). */
|
||||
@@ -4725,7 +4783,7 @@ struct yyjson_doc {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Unsafe JSON Value API (Implementation)
|
||||
* MARK: - Unsafe JSON Value API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
/*
|
||||
@@ -5054,7 +5112,7 @@ yyjson_api_inline void unsafe_yyjson_set_obj(void *val, size_t size) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Document API (Implementation)
|
||||
* MARK: - JSON Document API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_val *yyjson_doc_get_root(yyjson_doc *doc) {
|
||||
@@ -5081,7 +5139,7 @@ yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Type API (Implementation)
|
||||
* MARK: - JSON Value Type API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_is_raw(yyjson_val *val) {
|
||||
@@ -5143,7 +5201,7 @@ yyjson_api_inline bool yyjson_is_ctn(yyjson_val *val) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Content API (Implementation)
|
||||
* MARK: - JSON Value Content API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_type yyjson_get_type(yyjson_val *val) {
|
||||
@@ -5326,7 +5384,7 @@ yyjson_api_inline bool yyjson_set_str_noesc(yyjson_val *val, bool noesc) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Array API (Implementation)
|
||||
* MARK: - JSON Array API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline size_t yyjson_arr_size(yyjson_val *arr) {
|
||||
@@ -5376,7 +5434,7 @@ yyjson_api_inline yyjson_val *yyjson_arr_get_last(yyjson_val *arr) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Array Iterator API (Implementation)
|
||||
* MARK: - JSON Array Iterator API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_arr_iter_init(yyjson_val *arr,
|
||||
@@ -5415,7 +5473,7 @@ yyjson_api_inline yyjson_val *yyjson_arr_iter_next(yyjson_arr_iter *iter) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Object API (Implementation)
|
||||
* MARK: - JSON Object API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline size_t yyjson_obj_size(yyjson_val *obj) {
|
||||
@@ -5444,7 +5502,7 @@ yyjson_api_inline yyjson_val *yyjson_obj_getn(yyjson_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Object Iterator API (Implementation)
|
||||
* MARK: - JSON Object Iterator API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_obj_iter_init(yyjson_val *obj,
|
||||
@@ -5521,7 +5579,7 @@ yyjson_api_inline yyjson_val *yyjson_obj_iter_getn(yyjson_obj_iter *iter,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Structure (Implementation)
|
||||
* MARK: - Mutable JSON Structure (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -5637,7 +5695,7 @@ yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_val(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Document API (Implementation)
|
||||
* MARK: - Mutable JSON Document API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_root(yyjson_mut_doc *doc) {
|
||||
@@ -5652,7 +5710,7 @@ yyjson_api_inline void yyjson_mut_doc_set_root(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Type API (Implementation)
|
||||
* MARK: - Mutable JSON Value Type API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_is_raw(yyjson_mut_val *val) {
|
||||
@@ -5714,7 +5772,7 @@ yyjson_api_inline bool yyjson_mut_is_ctn(yyjson_mut_val *val) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Content API (Implementation)
|
||||
* MARK: - Mutable JSON Value Content API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_type yyjson_mut_get_type(yyjson_mut_val *val) {
|
||||
@@ -5893,7 +5951,7 @@ yyjson_api_inline bool yyjson_mut_set_obj(yyjson_mut_val *val) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Creation API (Implementation)
|
||||
* MARK: - Mutable JSON Value Creation API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
#define yyjson_mut_val_one(func) \
|
||||
@@ -6034,7 +6092,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_strncpy(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array API (Implementation)
|
||||
* MARK: - Mutable JSON Array API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline size_t yyjson_mut_arr_size(yyjson_mut_val *arr) {
|
||||
@@ -6070,7 +6128,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_last(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Iterator API (Implementation)
|
||||
* MARK: - Mutable JSON Array Iterator API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_arr_iter_init(yyjson_mut_val *arr,
|
||||
@@ -6130,7 +6188,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_remove(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Creation API (Implementation)
|
||||
* MARK: - Mutable JSON Array Creation API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_mut_val *yyjson_mut_arr(yyjson_mut_doc *doc) {
|
||||
@@ -6310,7 +6368,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strncpy(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Modification API (Implementation)
|
||||
* MARK: - Mutable JSON Array Modification API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_arr_insert(yyjson_mut_val *arr,
|
||||
@@ -6520,7 +6578,7 @@ yyjson_api_inline bool yyjson_mut_arr_rotate(yyjson_mut_val *arr,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Modification Convenience API (Implementation)
|
||||
* MARK: - Mutable JSON Array Modification Convenience API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_arr_add_val(yyjson_mut_val *arr,
|
||||
@@ -6686,7 +6744,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_obj(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object API (Implementation)
|
||||
* MARK: - Mutable JSON Object API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline size_t yyjson_mut_obj_size(yyjson_mut_val *obj) {
|
||||
@@ -6715,7 +6773,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_getn(yyjson_mut_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Iterator API (Implementation)
|
||||
* MARK: - Mutable JSON Object Iterator API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_obj_iter_init(yyjson_mut_val *obj,
|
||||
@@ -6806,7 +6864,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_getn(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Creation API (Implementation)
|
||||
* MARK: - Mutable JSON Object Creation API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_mut_val *yyjson_mut_obj(yyjson_mut_doc *doc) {
|
||||
@@ -6886,7 +6944,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_kv(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Modification API (Implementation)
|
||||
* MARK: - Mutable JSON Object Modification API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline void unsafe_yyjson_mut_obj_add(yyjson_mut_val *obj,
|
||||
@@ -7079,7 +7137,7 @@ yyjson_api_inline bool yyjson_mut_obj_rotate(yyjson_mut_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Modification Convenience API (Implementation)
|
||||
* MARK: - Mutable JSON Object Modification Convenience API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
#define yyjson_mut_obj_add_func(func) \
|
||||
@@ -7306,7 +7364,7 @@ yyjson_api_inline bool yyjson_mut_obj_rename_keyn(yyjson_mut_doc *doc,
|
||||
#if !defined(YYJSON_DISABLE_UTILS) || !YYJSON_DISABLE_UTILS
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Pointer API (Implementation)
|
||||
* MARK: - JSON Pointer API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
#define yyjson_ptr_set_err(_code, _msg) do { \
|
||||
@@ -7965,7 +8023,7 @@ yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value at Pointer API (Implementation)
|
||||
* MARK: - JSON Value at Pointer API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -8068,7 +8126,7 @@ yyjson_api_inline bool yyjson_ptr_get_str(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Deprecated
|
||||
* MARK: - Deprecated
|
||||
*============================================================================*/
|
||||
|
||||
/** @deprecated renamed to `yyjson_doc_ptr_get` */
|
||||
@@ -8152,7 +8210,7 @@ yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_get_pointer(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Compiler Hint End
|
||||
* MARK: - Compiler Hint End
|
||||
*============================================================================*/
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
+43
-29
@@ -10,21 +10,8 @@
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffParseModuleOptions(const char* key, const char* value)
|
||||
{
|
||||
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
|
||||
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (baseInfo->parseCommandOptions(baseInfo, key, value)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffPrepareCommandOption(FFdata* data)
|
||||
{
|
||||
FFOptionsModules* const options = &instance.config.modules;
|
||||
//If we don't have a custom structure, use the default one
|
||||
if(data->structure.length == 0)
|
||||
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
|
||||
@@ -33,54 +20,78 @@ void ffPrepareCommandOption(FFdata* data)
|
||||
ffPrepareCPUUsage();
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME))
|
||||
ffPrepareDiskIO(&options->diskIo);
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME))
|
||||
ffPrepareNetIO(&options->netIo);
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
|
||||
if(instance.config.general.multithreading)
|
||||
{
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
|
||||
ffPreparePublicIp(&options->publicIP);
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
|
||||
ffPrepareWeather(&options->weather);
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonConfig(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
|
||||
static void genJsonConfig(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
|
||||
{
|
||||
yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules");
|
||||
if (!modules)
|
||||
modules = yyjson_mut_obj_add_arr(doc, doc->root, "modules");
|
||||
|
||||
yyjson_mut_val* module = yyjson_mut_obj(doc);
|
||||
FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
|
||||
ffStrbufLowerCase(&type);
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
|
||||
|
||||
if (baseInfo->generateJsonConfig)
|
||||
baseInfo->generateJsonConfig(baseInfo, doc, module);
|
||||
if (instance.state.fullConfig)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_obj(doc);
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
|
||||
|
||||
if (yyjson_mut_obj_size(module) > 1)
|
||||
yyjson_mut_arr_add_val(modules, module);
|
||||
if (baseInfo->generateJsonConfig)
|
||||
baseInfo->generateJsonConfig(options, doc, module);
|
||||
|
||||
if (yyjson_mut_obj_size(module) > 1)
|
||||
yyjson_mut_arr_add_val(modules, module);
|
||||
else
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
else
|
||||
{
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
|
||||
static void genJsonResult(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* doc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
baseInfo->generateJsonResult(baseInfo, doc, module);
|
||||
baseInfo->generateJsonResult(options, doc, module);
|
||||
else
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
}
|
||||
|
||||
static void parseStructureCommand(
|
||||
const char* line,
|
||||
void (*fn)(FFModuleBaseInfo *baseInfo, yyjson_mut_doc* jsonDoc),
|
||||
void (*fn)(FFModuleBaseInfo* baseInfo, void* options, yyjson_mut_doc* jsonDoc),
|
||||
yyjson_mut_doc* jsonDoc
|
||||
)
|
||||
{
|
||||
@@ -91,10 +102,13 @@ static void parseStructureCommand(
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(line, baseInfo->name))
|
||||
{
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (__builtin_expect(jsonDoc != NULL, false))
|
||||
fn(baseInfo, jsonDoc);
|
||||
fn(baseInfo, optionBuf, jsonDoc);
|
||||
else
|
||||
baseInfo->printModule(baseInfo);
|
||||
baseInfo->printModule(optionBuf);
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ typedef struct FFdata
|
||||
bool configLoaded;
|
||||
} FFdata;
|
||||
|
||||
bool ffParseModuleOptions(const char* key, const char* value);
|
||||
void ffPrepareCommandOption(FFdata* data);
|
||||
void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc);
|
||||
void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "duration.h"
|
||||
|
||||
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
|
||||
bool spaceBeforeUnit = options->durationSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER;
|
||||
|
||||
if (totalSeconds < 60)
|
||||
{
|
||||
ffStrbufAppendUInt(result, totalSeconds);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
ffStrbufAppendS(result, options->durationAbbreviation ? "sec" : "second");
|
||||
if (totalSeconds != 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t seconds = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
if (seconds >= 30)
|
||||
totalSeconds++;
|
||||
|
||||
uint32_t minutes = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
uint32_t hours = (uint32_t) (totalSeconds % 24);
|
||||
totalSeconds /= 24;
|
||||
uint32_t days = (uint32_t) totalSeconds;
|
||||
|
||||
if (days > 0)
|
||||
{
|
||||
ffStrbufAppendUInt(result, days);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
{
|
||||
ffStrbufAppendC(result, 'd');
|
||||
|
||||
if (hours > 0 || minutes > 0)
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendS(result, days == 1 ? "day" : "days");
|
||||
|
||||
if (days >= 100)
|
||||
ffStrbufAppendS(result, "(!)");
|
||||
|
||||
if (hours > 0 || minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (hours > 0)
|
||||
{
|
||||
ffStrbufAppendUInt(result, hours);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
{
|
||||
ffStrbufAppendC(result, 'h');
|
||||
|
||||
if (minutes > 0)
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendS(result, hours == 1 ? "hour" : "hours");
|
||||
|
||||
if (minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (minutes > 0)
|
||||
{
|
||||
ffStrbufAppendUInt(result, minutes);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
ffStrbufAppendC(result, 'm');
|
||||
else
|
||||
ffStrbufAppendS(result, minutes == 1 ? "min" : "mins");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result);
|
||||
+10
-16
@@ -11,37 +11,31 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
switch(formatarg->type)
|
||||
{
|
||||
case FF_FORMAT_ARG_TYPE_INT:
|
||||
ffStrbufAppendF(buffer, "%" PRIi32, *(int32_t*)formatarg->value);
|
||||
ffStrbufAppendSInt(buffer, *(int32_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT:
|
||||
ffStrbufAppendF(buffer, "%" PRIu32, *(uint32_t*)formatarg->value);
|
||||
ffStrbufAppendUInt(buffer, *(uint32_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT64:
|
||||
ffStrbufAppendF(buffer, "%" PRIu64, *(uint64_t*)formatarg->value);
|
||||
ffStrbufAppendUInt(buffer, *(uint64_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT16:
|
||||
ffStrbufAppendF(buffer, "%" PRIu16, *(uint16_t*)formatarg->value);
|
||||
ffStrbufAppendUInt(buffer, *(uint16_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT8:
|
||||
ffStrbufAppendF(buffer, "%" PRIu8, *(uint8_t*)formatarg->value);
|
||||
ffStrbufAppendUInt(buffer, *(uint8_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_STRING:
|
||||
ffStrbufAppendS(buffer, (const char*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_STRBUF:
|
||||
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
|
||||
ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_FLOAT:
|
||||
if (instance.config.display.fractionNdigits >= 0)
|
||||
ffStrbufAppendF(buffer, "%.*f", instance.config.display.fractionNdigits, *(float*)formatarg->value);
|
||||
else
|
||||
ffStrbufAppendF(buffer, "%g", *(float*)formatarg->value);
|
||||
ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_DOUBLE:
|
||||
if (instance.config.display.fractionNdigits >= 0)
|
||||
ffStrbufAppendF(buffer, "%.*f", instance.config.display.fractionNdigits, *(double*)formatarg->value);
|
||||
else
|
||||
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
|
||||
ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_BOOL:
|
||||
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
|
||||
@@ -113,8 +107,8 @@ static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start,
|
||||
static inline bool formatArgSet(const FFformatarg* arg)
|
||||
{
|
||||
return arg->value != NULL && (
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) || //Also is false for NaN
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) || //Also is false for NaN
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "frequency.h"
|
||||
|
||||
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result)
|
||||
{
|
||||
if (mhz == 0)
|
||||
return false;
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
bool spaceBeforeUnit = options->freqSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER;
|
||||
int8_t ndigits = options->freqNdigits;
|
||||
|
||||
if (ndigits >= 0)
|
||||
{
|
||||
ffStrbufAppendDouble(result, mhz / 1000., ndigits);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
ffStrbufAppendS(result, "GHz");
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendUInt(result, mhz);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
ffStrbufAppendS(result, "MHz");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result);
|
||||
+2
-8
@@ -25,6 +25,7 @@ static void initState(FFstate* state)
|
||||
state->logoHeight = 0;
|
||||
state->keysHeight = 0;
|
||||
state->terminalLightTheme = false;
|
||||
state->titleFqdn = false;
|
||||
|
||||
ffPlatformInit(&state->platform);
|
||||
state->configDoc = NULL;
|
||||
@@ -42,14 +43,13 @@ static void defaultConfig(void)
|
||||
{
|
||||
ffOptionsInitLogo(&instance.config.logo);
|
||||
ffOptionsInitGeneral(&instance.config.general);
|
||||
ffOptionsInitModules(&instance.config.modules);
|
||||
ffOptionsInitDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
void ffInitInstance(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
//https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendations&view=msvc-170#utf-8-support
|
||||
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
|
||||
setlocale(LC_ALL, ".UTF8");
|
||||
#else
|
||||
// Never use `setlocale(LC_ALL, "")`
|
||||
@@ -96,11 +96,6 @@ static void chldSignalHandler(FF_MAYBE_UNUSED int signal)
|
||||
|
||||
void ffStart(void)
|
||||
{
|
||||
#ifdef FF_START_DETECTION_THREADS
|
||||
if(instance.config.general.multithreading)
|
||||
startDetectionThreads();
|
||||
#endif
|
||||
|
||||
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe && !instance.state.resultDoc;
|
||||
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
|
||||
|
||||
@@ -150,7 +145,6 @@ static void destroyConfig(void)
|
||||
{
|
||||
ffOptionsDestroyLogo(&instance.config.logo);
|
||||
ffOptionsDestroyGeneral(&instance.config.general);
|
||||
ffOptionsDestroyModules(&instance.config.modules);
|
||||
ffOptionsDestroyDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
|
||||
+19
-1
@@ -31,6 +31,7 @@ static inline FFNativeFD FFUnixFD2NativeFD(int unixfd)
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(3)
|
||||
static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* data)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
@@ -41,18 +42,22 @@ static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* dat
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content)
|
||||
{
|
||||
return ffWriteFDData(fd, content->length, content->chars);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 3)
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data);
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer)
|
||||
{
|
||||
return ffWriteFileData(fileName, buffer->length, buffer->chars);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(3)
|
||||
static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
@@ -66,26 +71,32 @@ static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data)
|
||||
#endif
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 3)
|
||||
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data);
|
||||
FF_C_NONNULL(2, 4)
|
||||
ssize_t ffReadFileDataRelative(FFNativeFD dfd, const char* fileName, size_t dataSize, void* data);
|
||||
|
||||
FF_C_NONNULL(2)
|
||||
bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer);
|
||||
FF_C_NONNULL(1, 2)
|
||||
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer);
|
||||
FF_C_NONNULL(2, 3)
|
||||
bool ffAppendFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer);
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufClear(buffer);
|
||||
return ffAppendFileBuffer(fileName, buffer);
|
||||
}
|
||||
|
||||
FF_C_NONNULL(2, 3)
|
||||
static inline bool ffReadFileBufferRelative(FFNativeFD dfd, const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufClear(buffer);
|
||||
return ffAppendFileBufferRelative(dfd, fileName, buffer);
|
||||
}
|
||||
|
||||
//Bit flags, combine with |
|
||||
typedef enum __attribute__((__packed__)) FFPathType
|
||||
{
|
||||
FF_PATHTYPE_FILE = 1 << 0,
|
||||
@@ -94,6 +105,7 @@ typedef enum __attribute__((__packed__)) FFPathType
|
||||
FF_PATHTYPE_FORCE_UNSIGNED = UINT8_MAX,
|
||||
} FFPathType;
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -136,11 +148,13 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_C_NONNULL(1, 2)
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out);
|
||||
|
||||
#define FF_IO_TERM_RESP_WAIT_MS 100 // #554
|
||||
|
||||
FF_C_SCANF(3, 4)
|
||||
FF_C_NONNULL(1, 3)
|
||||
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...);
|
||||
|
||||
// Not thread safe!
|
||||
@@ -157,6 +171,7 @@ static inline void ffUnsuppressIO(bool* suppressed)
|
||||
|
||||
void ffListFilesRecursively(const char* path, bool pretty);
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapClose(FFNativeFD* pfd)
|
||||
{
|
||||
assert(pfd);
|
||||
@@ -176,6 +191,7 @@ static inline bool wrapClose(FFNativeFD* pfd)
|
||||
}
|
||||
#define FF_AUTO_CLOSE_FD __attribute__((__cleanup__(wrapClose)))
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
static inline bool wrapFclose(FILE** pfile)
|
||||
{
|
||||
assert(pfile);
|
||||
@@ -186,6 +202,7 @@ static inline bool wrapFclose(FILE** pfile)
|
||||
}
|
||||
#define FF_AUTO_CLOSE_FILE __attribute__((__cleanup__(wrapFclose)))
|
||||
|
||||
FF_C_NONNULL(1)
|
||||
#ifndef _WIN32
|
||||
static inline bool wrapClosedir(DIR** pdir)
|
||||
{
|
||||
@@ -207,6 +224,7 @@ static inline bool wrapClosedir(HANDLE* pdir)
|
||||
#endif
|
||||
#define FF_AUTO_CLOSE_DIR __attribute__((__cleanup__(wrapClosedir)))
|
||||
|
||||
FF_C_NONNULL(1, 2, 3)
|
||||
static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char* fileSubpath, FFstrbuf* result)
|
||||
{
|
||||
// configDirs is a list of FFstrbufs include the trailing slash
|
||||
|
||||
+82
-42
@@ -12,52 +12,57 @@
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffJsonConfigParseModuleArgs(const char* key, yyjson_val* val, FFModuleArgs* moduleArgs)
|
||||
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs)
|
||||
{
|
||||
if(ffStrEqualsIgnCase(key, "key"))
|
||||
if (unsafe_yyjson_equals_str(key, "type") || unsafe_yyjson_equals_str(key, "condition"))
|
||||
return true;
|
||||
|
||||
if (unsafe_yyjson_equals_str(key, "key"))
|
||||
{
|
||||
ffStrbufSetNS(&moduleArgs->key, (uint32_t) yyjson_get_len(val), yyjson_get_str(val));
|
||||
ffStrbufSetJsonVal(&moduleArgs->key, val);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "format"))
|
||||
else if (unsafe_yyjson_equals_str(key, "format"))
|
||||
{
|
||||
ffStrbufSetNS(&moduleArgs->outputFormat, (uint32_t) yyjson_get_len(val), yyjson_get_str(val));
|
||||
ffStrbufSetJsonVal(&moduleArgs->outputFormat, val);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "outputColor"))
|
||||
else if (unsafe_yyjson_equals_str(key, "outputColor"))
|
||||
{
|
||||
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->outputColor);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "keyColor"))
|
||||
else if (unsafe_yyjson_equals_str(key, "keyColor"))
|
||||
{
|
||||
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->keyColor);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "keyWidth"))
|
||||
else if (unsafe_yyjson_equals_str(key, "keyWidth"))
|
||||
{
|
||||
moduleArgs->keyWidth = (uint32_t) yyjson_get_uint(val);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(key, "keyIcon"))
|
||||
else if (unsafe_yyjson_equals_str(key, "keyIcon"))
|
||||
{
|
||||
ffStrbufSetS(&moduleArgs->keyIcon, yyjson_get_str(val));
|
||||
ffStrbufSetJsonVal(&moduleArgs->keyIcon, val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* defaultModuleArgs, FFModuleArgs* moduleArgs)
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs)
|
||||
{
|
||||
if (!ffStrbufEqual(&defaultModuleArgs->key, &moduleArgs->key))
|
||||
if (moduleArgs->key.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "key", &moduleArgs->key);
|
||||
if (!ffStrbufEqual(&defaultModuleArgs->outputFormat, &moduleArgs->outputFormat))
|
||||
if (moduleArgs->outputFormat.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "format", &moduleArgs->outputFormat);
|
||||
if (!ffStrbufEqual(&defaultModuleArgs->keyColor, &moduleArgs->keyColor))
|
||||
if (moduleArgs->outputColor.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "outputColor", &moduleArgs->outputColor);
|
||||
if (moduleArgs->keyColor.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "keyColor", &moduleArgs->keyColor);
|
||||
if (moduleArgs->keyWidth != defaultModuleArgs->keyWidth)
|
||||
if (moduleArgs->keyWidth > 0)
|
||||
yyjson_mut_obj_add_uint(doc, module, "keyWidth", moduleArgs->keyWidth);
|
||||
if (!ffStrbufEqual(&defaultModuleArgs->keyIcon, &moduleArgs->keyIcon))
|
||||
if (moduleArgs->keyIcon.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "keyIcon", &moduleArgs->keyIcon);
|
||||
}
|
||||
|
||||
@@ -96,16 +101,6 @@ const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair p
|
||||
return "Invalid enum value type; must be a string or integer";
|
||||
}
|
||||
|
||||
static inline void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
baseInfo->generateJsonResult(baseInfo, doc, module);
|
||||
else
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
}
|
||||
|
||||
static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_mut_doc* jsonDoc)
|
||||
{
|
||||
if(!ffCharIsEnglishAlphabet(type[0])) return false;
|
||||
@@ -115,20 +110,47 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(type, baseInfo->name))
|
||||
{
|
||||
if (jsonVal) baseInfo->parseJsonObject(baseInfo, jsonVal);
|
||||
if (__builtin_expect(jsonDoc != NULL, false))
|
||||
genJsonResult(baseInfo, jsonDoc);
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (jsonVal) baseInfo->parseJsonObject(optionBuf, jsonVal);
|
||||
bool succeeded;
|
||||
if (jsonDoc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(jsonDoc, jsonDoc->root);
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
succeeded = baseInfo->generateJsonResult(optionBuf, jsonDoc, module);
|
||||
else
|
||||
{
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "error", "Unsupported for JSON format");
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
baseInfo->printModule(baseInfo);
|
||||
return true;
|
||||
succeeded = baseInfo->printModule(optionBuf);
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return succeeded;
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonDoc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(jsonDoc, jsonDoc->root);
|
||||
yyjson_mut_obj_add_strcpy(jsonDoc, module, "type", type);
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "error", "Unknown module type");
|
||||
}
|
||||
else
|
||||
{
|
||||
FFModuleArgs moduleArgs;
|
||||
ffOptionInitModuleArg(&moduleArgs, "");
|
||||
ffPrintError(type, 0, &moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown module type");
|
||||
ffOptionDestroyModuleArg(&moduleArgs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
{
|
||||
FFconfig* cfg = &instance.config;
|
||||
switch (type[0])
|
||||
{
|
||||
case 'b': case 'B': {
|
||||
@@ -139,32 +161,40 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
case 'd': case 'D': {
|
||||
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME))
|
||||
{
|
||||
if (module) cfg->modules.diskIo.moduleInfo.parseJsonObject(&cfg->modules.diskIo, module);
|
||||
ffPrepareDiskIO(&cfg->modules.diskIo);
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
if (module) ffDiskIOModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'n': case 'N': {
|
||||
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME))
|
||||
{
|
||||
if (module) cfg->modules.netIo.moduleInfo.parseJsonObject(&cfg->modules.netIo, module);
|
||||
ffPrepareNetIO(&cfg->modules.netIo);
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
if (module) ffNetIOModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': case 'P': {
|
||||
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME))
|
||||
{
|
||||
if (module) cfg->modules.publicIP.moduleInfo.parseJsonObject(&cfg->modules.publicIP, module);
|
||||
ffPreparePublicIp(&cfg->modules.publicIP);
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
if (module) ffPublicIPModuleInfo.parseJsonObject(&options, module);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'w': case 'W': {
|
||||
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME))
|
||||
{
|
||||
if (module) cfg->modules.weather.moduleInfo.parseJsonObject(&cfg->modules.weather, module);
|
||||
ffPrepareWeather(&cfg->modules.weather);
|
||||
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
if (module) ffWeatherModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -202,6 +232,7 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
if (!modules) return NULL;
|
||||
if (!yyjson_is_arr(modules)) return "Property 'modules' must be an array of strings or objects";
|
||||
|
||||
bool succeeded = true;
|
||||
int32_t thres = instance.config.display.stat;
|
||||
yyjson_val* item;
|
||||
size_t idx, max;
|
||||
@@ -238,6 +269,15 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
arch = yyjson_obj_get(conditions, "!arch");
|
||||
if (arch && matchesJsonArray(ffVersionResult.architecture, arch))
|
||||
continue;
|
||||
|
||||
yyjson_val* previousSucceeded = yyjson_obj_get(conditions, "succeeded");
|
||||
if (previousSucceeded && !unsafe_yyjson_is_null(previousSucceeded))
|
||||
{
|
||||
if (!unsafe_yyjson_is_bool(previousSucceeded))
|
||||
return "Property 'succeeded' in 'condition' must be a boolean";
|
||||
if (succeeded != unsafe_yyjson_get_bool(previousSucceeded))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
type = yyjson_get_str(yyjson_obj_get(module, "type"));
|
||||
@@ -250,8 +290,8 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
|
||||
if(prepare)
|
||||
prepareModuleJsonObject(type, module);
|
||||
else if(!parseModuleJsonObject(type, module, jsonDoc))
|
||||
return "Unknown module type";
|
||||
else
|
||||
succeeded = parseModuleJsonObject(type, module, jsonDoc);
|
||||
|
||||
if(!prepare && thres >= 0)
|
||||
{
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
bool ffJsonConfigParseModuleArgs(const char* key, yyjson_val* val, FFModuleArgs* moduleArgs);
|
||||
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs);
|
||||
const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[]);
|
||||
void ffPrintJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc);
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* defaultModuleArgs, FFModuleArgs* moduleArgs);
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs);
|
||||
|
||||
yyjson_api_inline yyjson_mut_val* yyjson_mut_strbuf(yyjson_mut_doc *doc, const FFstrbuf* buf) {
|
||||
return yyjson_mut_strncpy(doc, buf->chars, buf->length);
|
||||
|
||||
@@ -52,7 +52,7 @@ static void* libraryLoad(const char* path, int maxVersion)
|
||||
for(int i = maxVersion; i >= 0; --i)
|
||||
{
|
||||
uint32_t originalLength = pathbuf.length;
|
||||
ffStrbufAppendF(&pathbuf, "%i", i);
|
||||
ffStrbufAppendSInt(&pathbuf, i);
|
||||
|
||||
result = dlopen(pathbuf.chars, FF_DLOPEN_FLAGS);
|
||||
if(result != NULL)
|
||||
|
||||
+74
-74
@@ -1,69 +1,69 @@
|
||||
#include "fastfetch.h"
|
||||
#include "modules/modules.h"
|
||||
|
||||
static FFModuleBaseInfo* A[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* B[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.battery,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.bios,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.bluetooth,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.bluetoothRadio,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.board,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.bootmgr,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.break_,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.brightness,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.btrfs,
|
||||
&ffBatteryModuleInfo,
|
||||
&ffBiosModuleInfo,
|
||||
&ffBluetoothModuleInfo,
|
||||
&ffBluetoothRadioModuleInfo,
|
||||
&ffBoardModuleInfo,
|
||||
&ffBootmgrModuleInfo,
|
||||
&ffBreakModuleInfo,
|
||||
&ffBrightnessModuleInfo,
|
||||
&ffBtrfsModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* C[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.camera,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.chassis,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.command,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.colors,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.cpu,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.cpuCache,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.cpuUsage,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.cursor,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.custom,
|
||||
&ffCameraModuleInfo,
|
||||
&ffChassisModuleInfo,
|
||||
&ffCommandModuleInfo,
|
||||
&ffColorsModuleInfo,
|
||||
&ffCPUModuleInfo,
|
||||
&ffCPUCacheModuleInfo,
|
||||
&ffCPUUsageModuleInfo,
|
||||
&ffCursorModuleInfo,
|
||||
&ffCustomModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* D[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.dateTime,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.de,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.display,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.disk,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.diskIo,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.dns,
|
||||
&ffDateTimeModuleInfo,
|
||||
&ffDEModuleInfo,
|
||||
&ffDisplayModuleInfo,
|
||||
&ffDiskModuleInfo,
|
||||
&ffDiskIOModuleInfo,
|
||||
&ffDNSModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* E[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.editor,
|
||||
&ffEditorModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* F[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.font,
|
||||
&ffFontModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* G[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.gamepad,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.gpu,
|
||||
&ffGamepadModuleInfo,
|
||||
&ffGPUModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* H[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.host,
|
||||
&ffHostModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* I[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.icons,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.initSystem,
|
||||
&ffIconsModuleInfo,
|
||||
&ffInitSystemModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -72,47 +72,47 @@ static FFModuleBaseInfo* J[] = {
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* K[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.kernel,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.keyboard,
|
||||
&ffKernelModuleInfo,
|
||||
&ffKeyboardModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* L[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.lm,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.loadavg,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.locale,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.localIP,
|
||||
&ffLMModuleInfo,
|
||||
&ffLoadavgModuleInfo,
|
||||
&ffLocaleModuleInfo,
|
||||
&ffLocalIPModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* M[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.media,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.memory,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.monitor,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.mouse,
|
||||
&ffMediaModuleInfo,
|
||||
&ffMemoryModuleInfo,
|
||||
&ffMonitorModuleInfo,
|
||||
&ffMouseModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* N[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.netIo,
|
||||
&ffNetIOModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* O[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.openCL,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.openGL,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.os,
|
||||
&ffOpenCLModuleInfo,
|
||||
&ffOpenGLModuleInfo,
|
||||
&ffOSModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* P[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.packages,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.physicalDisk,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.physicalMemory,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.player,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.powerAdapter,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.processes,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.publicIP,
|
||||
&ffPackagesModuleInfo,
|
||||
&ffPhysicalDiskModuleInfo,
|
||||
&ffPhysicalMemoryModuleInfo,
|
||||
&ffPlayerModuleInfo,
|
||||
&ffPowerAdapterModuleInfo,
|
||||
&ffProcessesModuleInfo,
|
||||
&ffPublicIPModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -125,42 +125,42 @@ static FFModuleBaseInfo* R[] = {
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* S[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.separator,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.shell,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.sound,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.swap,
|
||||
&ffSeparatorModuleInfo,
|
||||
&ffShellModuleInfo,
|
||||
&ffSoundModuleInfo,
|
||||
&ffSwapModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* T[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.terminal,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.terminalFont,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.terminalSize,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.terminalTheme,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.title,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.theme,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.tpm,
|
||||
&ffTerminalModuleInfo,
|
||||
&ffTerminalFontModuleInfo,
|
||||
&ffTerminalSizeModuleInfo,
|
||||
&ffTerminalThemeModuleInfo,
|
||||
&ffTitleModuleInfo,
|
||||
&ffThemeModuleInfo,
|
||||
&ffTPMModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* U[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.uptime,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.users,
|
||||
&ffUptimeModuleInfo,
|
||||
&ffUsersModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* V[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.version,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.vulkan,
|
||||
&ffVersionModuleInfo,
|
||||
&ffVulkanModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* W[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.wallpaper,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.weather,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.wm,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.wifi,
|
||||
(FFModuleBaseInfo*) &instance.config.modules.wmTheme,
|
||||
&ffWallpaperModuleInfo,
|
||||
&ffWeatherModuleInfo,
|
||||
&ffWMModuleInfo,
|
||||
&ffWifiModuleInfo,
|
||||
&ffWMThemeModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -173,7 +173,7 @@ static FFModuleBaseInfo* Y[] = {
|
||||
};
|
||||
|
||||
static FFModuleBaseInfo* Z[] = {
|
||||
(FFModuleBaseInfo*) &instance.config.modules.zpool,
|
||||
&ffZpoolModuleInfo,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
+13
-19
@@ -2,29 +2,23 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#else
|
||||
#define IF_NAMESIZE 0
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex);
|
||||
enum { IF_INDEX_UNINITIALIZED = (uint32_t) -1, IF_INDEX_INVALID = (uint32_t) -2 };
|
||||
static uint32_t ifIndex = IF_INDEX_UNINITIALIZED;
|
||||
static char ifName[IF_NAMESIZE + 1];
|
||||
|
||||
static inline void init()
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void)
|
||||
{
|
||||
if (ifIndex == (uint32_t) IF_INDEX_UNINITIALIZED && !ffNetifGetDefaultRouteImpl(ifName, &ifIndex))
|
||||
ifIndex = (uint32_t) IF_INDEX_INVALID;
|
||||
static FFNetifDefaultRouteResult result;
|
||||
if (result.status == FF_NETIF_UNINITIALIZED) {
|
||||
result.status = ffNetifGetDefaultRouteImplV4(&result) ? FF_NETIF_OK : FF_NETIF_INVALID;
|
||||
}
|
||||
return &result;
|
||||
}
|
||||
|
||||
const char* ffNetifGetDefaultRouteIfName()
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void)
|
||||
{
|
||||
init();
|
||||
return ifName;
|
||||
}
|
||||
|
||||
uint32_t ffNetifGetDefaultRouteIfIndex()
|
||||
{
|
||||
init();
|
||||
return ifIndex;
|
||||
static FFNetifDefaultRouteResult result;
|
||||
if (result.status == FF_NETIF_UNINITIALIZED) {
|
||||
result.status = ffNetifGetDefaultRouteImplV6(&result) ? FF_NETIF_OK : FF_NETIF_INVALID;
|
||||
}
|
||||
return &result;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,28 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
const char* ffNetifGetDefaultRouteIfName();
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
uint32_t ffNetifGetDefaultRouteIfIndex();
|
||||
typedef enum __attribute__((__packed__)) FFNetifDefaultRouteResultStatus {
|
||||
FF_NETIF_UNINITIALIZED,
|
||||
FF_NETIF_INVALID,
|
||||
FF_NETIF_OK
|
||||
} FFNetifDefaultRouteResultStatus;
|
||||
|
||||
typedef struct FFNetifDefaultRouteResult {
|
||||
uint32_t ifIndex;
|
||||
|
||||
#ifndef _WIN32
|
||||
char ifName[IF_NAMESIZE + 1];
|
||||
uint32_t preferredSourceAddrV4;
|
||||
#endif
|
||||
enum FFNetifDefaultRouteResultStatus status;
|
||||
} FFNetifDefaultRouteResult;
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result);
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result);
|
||||
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV4(void);
|
||||
const FFNetifDefaultRouteResult* ffNetifGetDefaultRouteV6(void);
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#include "netif.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
|
||||
#if __APPLE__
|
||||
// https://github.com/apple-oss-distributions/network_cmds/blob/8f38231438e6a4d16ef8015e97e12c2c05105644/rtsol.tproj/if.c#L243
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(uint32_t))
|
||||
#elif __sun
|
||||
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L339
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#else
|
||||
#error unknown platform
|
||||
#endif
|
||||
|
||||
static struct sockaddr *
|
||||
get_rt_address(struct rt_msghdr *rtm, int desired)
|
||||
{
|
||||
struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
|
||||
|
||||
for (int i = 0; i < RTAX_MAX; i++)
|
||||
{
|
||||
if (rtm->rtm_addrs & (1 << i))
|
||||
{
|
||||
if ((1 << i) == desired)
|
||||
return sa;
|
||||
|
||||
#ifndef __sun
|
||||
uint32_t salen = sa->sa_len;
|
||||
#else
|
||||
uint32_t salen;
|
||||
// https://github.com/illumos/illumos-gate/blob/95b8c88950fa7b19af46bc63230137cf96b0bff7/usr/src/cmd/cmd-inet/usr.sbin/route.c#L2941
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
salen = sizeof (struct sockaddr_in);
|
||||
break;
|
||||
case AF_LINK:
|
||||
salen = sizeof (struct sockaddr_dl);
|
||||
break;
|
||||
case AF_INET6:
|
||||
salen = sizeof (struct sockaddr_in6);
|
||||
break;
|
||||
default:
|
||||
salen = sizeof (struct sockaddr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
sa = (struct sockaddr *)(ROUNDUP(salen) + (char *)sa);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET);
|
||||
if (pfRoute < 0)
|
||||
return false;
|
||||
|
||||
{
|
||||
struct timeval timeout = {1, 0};
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
int pid = getpid();
|
||||
|
||||
struct {
|
||||
struct rt_msghdr hdr;
|
||||
struct sockaddr_in dst;
|
||||
uint8_t data[512];
|
||||
} rtmsg = {
|
||||
.hdr = {
|
||||
.rtm_type = RTM_GET,
|
||||
.rtm_flags = RTF_UP | RTF_GATEWAY,
|
||||
.rtm_version = RTM_VERSION,
|
||||
.rtm_addrs = RTA_DST | RTA_IFP | RTA_IFA,
|
||||
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
|
||||
.rtm_pid = pid,
|
||||
.rtm_seq = 1,
|
||||
},
|
||||
.dst = {
|
||||
.sin_family = AF_INET,
|
||||
#ifndef __sun
|
||||
.sin_len = sizeof(rtmsg.dst),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
|
||||
return false;
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid))
|
||||
;
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
if (sdl
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
// Get the preferred source address
|
||||
struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(&rtmsg.hdr, RTA_IFA);
|
||||
if (src && src->sin_family == AF_INET)
|
||||
result->preferredSourceAddrV4 = src->sin_addr.s_addr;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
|
||||
if (pfRoute < 0)
|
||||
return false;
|
||||
|
||||
{
|
||||
struct timeval timeout = {1, 0};
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
|
||||
int pid = getpid();
|
||||
|
||||
struct {
|
||||
struct rt_msghdr hdr;
|
||||
struct sockaddr_in6 dst;
|
||||
uint8_t data[512];
|
||||
} rtmsg = {
|
||||
.hdr = {
|
||||
.rtm_type = RTM_GET,
|
||||
.rtm_flags = RTF_UP | RTF_GATEWAY,
|
||||
.rtm_version = RTM_VERSION,
|
||||
.rtm_addrs = RTA_DST | RTA_IFP,
|
||||
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
|
||||
.rtm_pid = pid,
|
||||
.rtm_seq = 2,
|
||||
},
|
||||
.dst = {
|
||||
.sin6_family = AF_INET6,
|
||||
#ifndef __sun
|
||||
.sin6_len = sizeof(rtmsg.dst),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
if (send(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen, 0) != rtmsg.hdr.rtm_msglen)
|
||||
return false;
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == pid))
|
||||
;
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
|
||||
#endif
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
if (sdl
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -8,25 +8,24 @@
|
||||
#include <net/route.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#define ROUNDUP2(a, n) ((a) > 0 ? (1 + (((a) - 1U) | ((n) - 1))) : (n))
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
#elif defined(__NetBSD__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
#elif defined(__OpenBSD__)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), sizeof(int))
|
||||
#elif defined(__sun)
|
||||
# define ROUNDUP(a) ROUNDUP2((a), _SS_ALIGNSIZE)
|
||||
#if __DragonFly__
|
||||
// https://github.com/DragonFlyBSD/DragonFlyBSD/blob/cf0aa2f1e47a3f0a6055fe427563cb3f3e627064/sys/net/route.h#L315C9-L315C19
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#elif __FreeBSD__
|
||||
// https://github.com/freebsd/freebsd-src/blob/e4c0ecba44b20ebb2e4d80978c2cb6d16b730cb9/sys/net/route.h#L368C9-L368C16
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#elif __NetBSD__
|
||||
// https://github.com/NetBSD/src/blob/29beb637d057520c0ed37ac2cde966f7cc0cadf4/sys/net/route.h#L330
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(uint64_t))
|
||||
#elif __OpenBSD__
|
||||
// https://github.com/openbsd/src/blob/ca647cfa4ec3ccb8360714bc0ebc32a394f7fb6a/regress/sys/netinet/bindconnect/bindconnect.c#L250
|
||||
#define ROUNDUP(a) ROUNDUP2((a), sizeof(long))
|
||||
#else
|
||||
# error unknown platform
|
||||
#error unknown platform
|
||||
#endif
|
||||
|
||||
static struct sockaddr *
|
||||
@@ -40,23 +39,18 @@ get_rt_address(struct rt_msghdr *rtm, int desired)
|
||||
{
|
||||
if ((1 << i) == desired)
|
||||
return sa;
|
||||
#ifdef __sun
|
||||
sa = (struct sockaddr *)(ROUNDUP(sizeof(struct sockaddr)) + (char *)sa);
|
||||
#else
|
||||
sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
#if defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
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)
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0)
|
||||
return false;
|
||||
|
||||
FF_AUTO_FREE char* buf = malloc(needed);
|
||||
@@ -71,80 +65,62 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
|
||||
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && (sa->sa_family == AF_INET))
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET))
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl->sdl_family == AF_LINK)
|
||||
if (sdl && sdl->sdl_family == AF_LINK)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(iface, sdl->sdl_data, sdl->sdl_nlen);
|
||||
iface[sdl->sdl_nlen] = '\0';
|
||||
*ifIndex = sdl->sdl_index;
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
// Get the preferred source address
|
||||
struct sockaddr_in* src = (struct sockaddr_in*)get_rt_address(rtm, RTA_IFA);
|
||||
if (src && src->sin_family == AF_INET)
|
||||
result->preferredSourceAddrV4 = src->sin_addr.s_addr;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
//https://github.com/hashPirate/copenheimer-masscan-fork/blob/36f1ed9f7b751a7dccd5ed27874e2e703db7d481/src/rawsock-getif.c#L104
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(PF_ROUTE, SOCK_RAW, AF_INET);
|
||||
if (pfRoute < 0)
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
int mib[6] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY};
|
||||
size_t needed;
|
||||
|
||||
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0 || needed == 0)
|
||||
return false;
|
||||
|
||||
{
|
||||
struct timeval timeout = {1, 0};
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
setsockopt(pfRoute, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout));
|
||||
}
|
||||
FF_AUTO_FREE char* buf = malloc(needed);
|
||||
|
||||
int pid = getpid();
|
||||
|
||||
struct {
|
||||
struct rt_msghdr hdr;
|
||||
struct sockaddr_in dst;
|
||||
uint8_t data[512];
|
||||
} rtmsg = {
|
||||
.hdr = {
|
||||
.rtm_type = RTM_GET,
|
||||
.rtm_flags = RTF_UP | RTF_GATEWAY,
|
||||
.rtm_version = RTM_VERSION,
|
||||
.rtm_addrs = RTA_DST | RTA_IFP,
|
||||
.rtm_msglen = sizeof(rtmsg.hdr) + sizeof(rtmsg.dst),
|
||||
.rtm_pid = pid,
|
||||
.rtm_seq = 1,
|
||||
},
|
||||
.dst = {
|
||||
.sin_family = AF_INET,
|
||||
#ifndef __sun
|
||||
.sin_len = sizeof(rtmsg.dst),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
if (write(pfRoute, &rtmsg, rtmsg.hdr.rtm_msglen) != rtmsg.hdr.rtm_msglen)
|
||||
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
|
||||
return false;
|
||||
|
||||
while (read(pfRoute, &rtmsg, sizeof(rtmsg)) > 0)
|
||||
char* lim = buf + needed;
|
||||
struct rt_msghdr* rtm;
|
||||
for (char* next = buf; next < lim; next += rtm->rtm_msglen)
|
||||
{
|
||||
if (rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == pid)
|
||||
rtm = (struct rt_msghdr *)next;
|
||||
struct sockaddr* sa = (struct sockaddr *)(rtm + 1);
|
||||
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET6))
|
||||
{
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(&rtmsg.hdr, RTA_IFP);
|
||||
if (sdl
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
)
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl *)get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl && sdl->sdl_family == AF_LINK)
|
||||
{
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
memcpy(iface, sdl->sdl_data, sdl->sdl_nlen);
|
||||
iface[sdl->sdl_nlen] = '\0';
|
||||
*ifIndex = sdl->sdl_index;
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "netif.h"
|
||||
#include "common/io/io.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/route", "r");
|
||||
|
||||
if (!netRoute) return false;
|
||||
|
||||
// skip first line
|
||||
FF_UNUSED(fscanf(netRoute, "%*[^\n]\n"));
|
||||
unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu, ...
|
||||
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", result->ifName, &destination) == 2)
|
||||
{
|
||||
if (destination != 0) continue;
|
||||
result->ifIndex = if_nametoindex(result->ifName);
|
||||
// TODO: Get the preferred source address
|
||||
return true;
|
||||
}
|
||||
result->ifName[0] = '0';
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
// TODO: AF_INET6
|
||||
FF_UNUSED(result);
|
||||
return false;
|
||||
}
|
||||
@@ -11,9 +11,8 @@
|
||||
|
||||
// loosely based on Haiku's src/bin/network/route/route.cpp
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
// TODO: AF_INET6
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET);
|
||||
if (pfRoute < 0)
|
||||
return false;
|
||||
@@ -42,8 +41,11 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
|
||||
while (interface < end) {
|
||||
if (interface->ifr_route.flags & RTF_DEFAULT) {
|
||||
strlcpy(iface, interface->ifr_name, IF_NAMESIZE);
|
||||
*ifIndex = if_nametoindex(interface->ifr_name);
|
||||
// interface->ifr_metric?
|
||||
strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
|
||||
result->ifIndex = if_nametoindex(interface->ifr_name);
|
||||
if (interface->ifr_route.source)
|
||||
result->preferredSourceAddrV4 = ((struct sockaddr_in*)interface->ifr_route.source)->sin_addr.s_addr;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,9 +57,56 @@ bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
if (interface->ifr_route.gateway != NULL)
|
||||
addressSize += interface->ifr_route.gateway->sa_len;
|
||||
|
||||
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE
|
||||
+ sizeof(struct route_entry) + addressSize);
|
||||
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET6);
|
||||
if (pfRoute < 0)
|
||||
return false;
|
||||
|
||||
struct ifconf config;
|
||||
config.ifc_len = sizeof(config.ifc_value);
|
||||
if (ioctl(pfRoute, SIOCGRTSIZE, &config, sizeof(struct ifconf)) < 0)
|
||||
return false;
|
||||
|
||||
int size = config.ifc_value;
|
||||
if (size <= 0)
|
||||
return false;
|
||||
|
||||
FF_AUTO_FREE void *buffer = malloc((size_t) size);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.ifc_len = size;
|
||||
config.ifc_buf = buffer;
|
||||
if (ioctl(pfRoute, SIOCGRTTABLE, &config, sizeof(struct ifconf)) < 0)
|
||||
return false;
|
||||
|
||||
struct ifreq *interface = (struct ifreq*)buffer;
|
||||
struct ifreq *end = (struct ifreq*)((uint8_t*)buffer + size);
|
||||
|
||||
while (interface < end) {
|
||||
if (interface->ifr_route.flags & RTF_DEFAULT) {
|
||||
strlcpy(result->ifName, interface->ifr_name, IF_NAMESIZE);
|
||||
result->ifIndex = if_nametoindex(interface->ifr_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t addressSize = 0;
|
||||
if (interface->ifr_route.destination != NULL)
|
||||
addressSize += interface->ifr_route.destination->sa_len;
|
||||
if (interface->ifr_route.mask != NULL)
|
||||
addressSize += interface->ifr_route.mask->sa_len;
|
||||
if (interface->ifr_route.gateway != NULL)
|
||||
addressSize += interface->ifr_route.gateway->sa_len;
|
||||
|
||||
interface = (struct ifreq*)((addr_t)interface + IF_NAMESIZE + sizeof(struct route_entry) + addressSize);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+412
-32
@@ -1,52 +1,432 @@
|
||||
#include "netif.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
|
||||
static bool getDefaultRouteIPv4(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/route", "r");
|
||||
if (!netRoute) return false;
|
||||
FF_DEBUG("Starting IPv4 default route detection");
|
||||
|
||||
// skip first line
|
||||
FF_UNUSED(fscanf(netRoute, "%*[^\n]\n"));
|
||||
|
||||
unsigned long long destination; //, gateway, flags, refCount, use, metric, mask, mtu, ...
|
||||
while (fscanf(netRoute, "%" FF_STR(IF_NAMESIZE) "s%llx%*[^\n]", iface, &destination) == 2)
|
||||
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
if (destination != 0) continue;
|
||||
*ifIndex = if_nametoindex(iface);
|
||||
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
|
||||
|
||||
unsigned pid = (unsigned) getpid();
|
||||
FF_DEBUG("Process PID: %u", pid);
|
||||
|
||||
// Bind socket
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Let kernel choose PID
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Successfully bound socket");
|
||||
|
||||
struct __attribute__((__packed__)) {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtmsg rtm;
|
||||
struct rtattr rta;
|
||||
uint32_t table;
|
||||
} req = {
|
||||
// Netlink message header
|
||||
.nlh = {
|
||||
.nlmsg_len = sizeof(req),
|
||||
.nlmsg_type = RTM_GETROUTE,
|
||||
.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
|
||||
.nlmsg_seq = 1,
|
||||
.nlmsg_pid = pid,
|
||||
},
|
||||
// Route message
|
||||
.rtm = {
|
||||
.rtm_family = AF_INET,
|
||||
.rtm_dst_len = 0, // Match all destinations
|
||||
.rtm_src_len = 0, // Match all sources
|
||||
.rtm_tos = 0,
|
||||
.rtm_table = RT_TABLE_UNSPEC,
|
||||
.rtm_protocol = RTPROT_UNSPEC,
|
||||
.rtm_scope = RT_SCOPE_UNIVERSE,
|
||||
.rtm_type = RTN_UNSPEC,
|
||||
.rtm_flags = 0,
|
||||
},
|
||||
// Route attribute for main table
|
||||
.rta = {
|
||||
.rta_len = RTA_LENGTH(sizeof(uint32_t)),
|
||||
.rta_type = RTA_TABLE,
|
||||
},
|
||||
.table = RT_TABLE_MAIN,
|
||||
};
|
||||
|
||||
struct sockaddr_nl dest_addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Kernel
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0,
|
||||
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
|
||||
|
||||
if (sent != sizeof(req)) {
|
||||
FF_DEBUG("Failed to send netlink request: sent=%zd, expected=%zu", sent, sizeof(req));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Sent netlink request: %zd bytes", sent);
|
||||
|
||||
struct sockaddr_nl src_addr = {};
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
|
||||
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
|
||||
uint32_t minMetric = UINT32_MAX;
|
||||
int routeCount = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr*)&src_addr, &src_addr_len);
|
||||
|
||||
if (received < 0) {
|
||||
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (received >= (ssize_t)sizeof(buffer)) {
|
||||
FF_DEBUG("Received truncated message: received %zd, bufsize %zu", received, sizeof(buffer));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Received netlink response: %zd bytes", received);
|
||||
if (received == 0) {
|
||||
FF_DEBUG("Received zero-length netlink response, ending processing");
|
||||
break;
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t metric;
|
||||
uint32_t ifindex;
|
||||
uint32_t prefsrc;
|
||||
} entry;
|
||||
|
||||
for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
|
||||
NLMSG_OK(nlh, received);
|
||||
nlh = NLMSG_NEXT(nlh, received))
|
||||
{
|
||||
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid)
|
||||
continue;
|
||||
if (nlh->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
FF_DEBUG("Received NLMSG_DONE, processed %d routes", routeCount);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type == NLMSG_ERROR) {
|
||||
FF_DEBUG("Netlink reports error: %s", strerror(-((struct nlmsgerr*)NLMSG_DATA(nlh))->error));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type != RTM_NEWROUTE) {
|
||||
FF_DEBUG("Skipping non-route message: type=%d", nlh->nlmsg_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
routeCount++;
|
||||
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
|
||||
if (rtm->rtm_family != AF_INET) {
|
||||
FF_DEBUG("Skipping non-IPv4 route #%d (family=%d)", routeCount, rtm->rtm_family);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rtm->rtm_dst_len != 0) {
|
||||
FF_DEBUG("Skipping non-default route #%d (dst_len=%d)", routeCount, rtm->rtm_dst_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_DEBUG("Processing IPv4 default route candidate #%d", routeCount);
|
||||
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
|
||||
|
||||
// Parse route attributes
|
||||
size_t rtm_len = RTM_PAYLOAD(nlh);
|
||||
for (struct rtattr* rta = RTM_RTA(rtm);
|
||||
RTA_OK(rta, rtm_len);
|
||||
rta = RTA_NEXT(rta, rtm_len))
|
||||
{
|
||||
if (RTA_PAYLOAD(rta) < sizeof(uint32_t))
|
||||
continue; // Skip invalid attributes
|
||||
|
||||
uint32_t rta_data = *(uint32_t*) RTA_DATA(rta);
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
FF_DEBUG("Unexpected RTA_DST: %s (len=%u)", inet_ntoa((struct in_addr) { .s_addr = rta_data }), rtm->rtm_dst_len);
|
||||
goto next;
|
||||
case RTA_OIF:
|
||||
entry.ifindex = rta_data;
|
||||
FF_DEBUG("Found interface index: %u", entry.ifindex);
|
||||
break;
|
||||
case RTA_GATEWAY:
|
||||
FF_DEBUG("Found gateway: %s", inet_ntoa(*(struct in_addr*)&rta_data));
|
||||
if (rta_data == 0) goto next;
|
||||
break;
|
||||
case RTA_PRIORITY:
|
||||
FF_DEBUG("Found metric: %u", rta_data);
|
||||
if (rta_data >= minMetric) goto next;
|
||||
entry.metric = rta_data;
|
||||
break;
|
||||
case RTA_PREFSRC:
|
||||
entry.prefsrc = rta_data;
|
||||
FF_DEBUG("Found preferred source: %s", inet_ntoa(*(struct in_addr*)&rta_data));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.ifindex == 0 || entry.metric >= minMetric)
|
||||
{
|
||||
next:
|
||||
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
continue;
|
||||
}
|
||||
minMetric = entry.metric;
|
||||
result->ifIndex = entry.ifindex;
|
||||
FF_DEBUG("Updated best route: ifindex=%u, metric=%u, prefsrc=%x", entry.ifindex, entry.metric, entry.prefsrc);
|
||||
result->preferredSourceAddrV4 = entry.prefsrc;
|
||||
if (minMetric == 0)
|
||||
{
|
||||
FF_DEBUG("Found zero metric route, stopping further processing");
|
||||
break; // Stop processing if we found a zero metric route
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (minMetric < UINT32_MAX)
|
||||
{
|
||||
if_indextoname(result->ifIndex, result->ifName);
|
||||
FF_DEBUG("Found default IPv4 route: interface=%s, index=%u, metric=%u", result->ifName, result->ifIndex, minMetric);
|
||||
return true;
|
||||
}
|
||||
iface[0] = '\0';
|
||||
FF_DEBUG("No IPv4 default route found");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool getDefaultRouteIPv6(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/net/ipv6_route", "r");
|
||||
if (!netRoute) return false;
|
||||
FF_DEBUG("Starting IPv6 default route detection");
|
||||
|
||||
uint32_t prefixLen;
|
||||
//destination, dest_prefix_len, source, src_prefix_len, next hop, metric, ref counter, use counter, flags, iface
|
||||
while (fscanf(netRoute, "%*s %x %*s %*s %*s %*s %*s %*s %*s %" FF_STR(IF_NAMESIZE) "s", &prefixLen, iface) == 2)
|
||||
FF_AUTO_CLOSE_FD int sock_fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if (sock_fd < 0)
|
||||
{
|
||||
if (prefixLen != 0) continue;
|
||||
*ifIndex = if_nametoindex(iface);
|
||||
FF_DEBUG("Failed to create netlink socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Created netlink socket: fd=%d", sock_fd);
|
||||
|
||||
unsigned pid = (unsigned) getpid();
|
||||
FF_DEBUG("Process PID: %u", pid);
|
||||
|
||||
// Bind socket
|
||||
struct sockaddr_nl addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Let kernel choose PID
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
if (bind(sock_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
||||
FF_DEBUG("Failed to bind socket: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Successfully bound socket");
|
||||
|
||||
struct __attribute__((__packed__)) {
|
||||
struct nlmsghdr nlh;
|
||||
struct rtmsg rtm;
|
||||
struct rtattr rta;
|
||||
uint32_t table;
|
||||
} req = {
|
||||
// Netlink message header
|
||||
.nlh = {
|
||||
.nlmsg_len = sizeof(req),
|
||||
.nlmsg_type = RTM_GETROUTE,
|
||||
.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
|
||||
.nlmsg_seq = 1,
|
||||
.nlmsg_pid = pid,
|
||||
},
|
||||
// Route message
|
||||
.rtm = {
|
||||
.rtm_family = AF_INET6, // IPv6 instead of IPv4
|
||||
.rtm_dst_len = 0, // Match all destinations
|
||||
.rtm_src_len = 0, // Match all sources
|
||||
.rtm_tos = 0,
|
||||
.rtm_table = RT_TABLE_UNSPEC,
|
||||
.rtm_protocol = RTPROT_UNSPEC,
|
||||
.rtm_scope = RT_SCOPE_UNIVERSE,
|
||||
.rtm_type = RTN_UNSPEC,
|
||||
.rtm_flags = 0,
|
||||
},
|
||||
// Route attribute for main table
|
||||
.rta = {
|
||||
.rta_len = RTA_LENGTH(sizeof(uint32_t)),
|
||||
.rta_type = RTA_TABLE,
|
||||
},
|
||||
.table = RT_TABLE_MAIN,
|
||||
};
|
||||
|
||||
struct sockaddr_nl dest_addr = {
|
||||
.nl_family = AF_NETLINK,
|
||||
.nl_pid = 0, // Kernel
|
||||
.nl_groups = 0, // No multicast groups
|
||||
};
|
||||
|
||||
ssize_t sent = sendto(sock_fd, &req, sizeof(req), 0,
|
||||
(struct sockaddr*)&dest_addr, sizeof(dest_addr));
|
||||
|
||||
if (sent != sizeof(req)) {
|
||||
FF_DEBUG("Failed to send netlink request: sent=%zd, expected=%zu", sent, sizeof(req));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Sent netlink request: %zd bytes", sent);
|
||||
|
||||
struct sockaddr_nl src_addr = {};
|
||||
socklen_t src_addr_len = sizeof(src_addr);
|
||||
|
||||
uint8_t buffer[1024 * 16]; // 16 KB buffer should be sufficient
|
||||
uint32_t minMetric = UINT32_MAX;
|
||||
int routeCount = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
ssize_t received = recvfrom(sock_fd, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr*)&src_addr, &src_addr_len);
|
||||
|
||||
if (received < 0) {
|
||||
FF_DEBUG("Failed to receive netlink response: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (received >= (ssize_t)sizeof(buffer)) {
|
||||
FF_DEBUG("Received truncated message: received %zd, bufsize %zu", received, sizeof(buffer));
|
||||
return false;
|
||||
}
|
||||
FF_DEBUG("Received netlink response: %zd bytes", received);
|
||||
if (received == 0) {
|
||||
FF_DEBUG("Received zero-length netlink response, ending processing");
|
||||
break;
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t metric;
|
||||
uint32_t ifindex;
|
||||
} entry;
|
||||
|
||||
for (const struct nlmsghdr* nlh = (struct nlmsghdr*)buffer;
|
||||
NLMSG_OK(nlh, received);
|
||||
nlh = NLMSG_NEXT(nlh, received))
|
||||
{
|
||||
if (nlh->nlmsg_seq != 1 || nlh->nlmsg_pid != pid)
|
||||
continue;
|
||||
if (nlh->nlmsg_type == NLMSG_DONE)
|
||||
{
|
||||
FF_DEBUG("Received NLMSG_DONE, processed %d routes", routeCount);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type == NLMSG_ERROR) {
|
||||
FF_DEBUG("Netlink reports error: %s", strerror(-((struct nlmsgerr*)NLMSG_DATA(nlh))->error));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nlh->nlmsg_type != RTM_NEWROUTE) {
|
||||
FF_DEBUG("Skipping non-route message: type=%d", nlh->nlmsg_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
routeCount++;
|
||||
struct rtmsg* rtm = (struct rtmsg*)NLMSG_DATA(nlh);
|
||||
if (rtm->rtm_family != AF_INET6) {
|
||||
FF_DEBUG("Skipping non-IPv6 route #%d (family=%d)", routeCount, rtm->rtm_family);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rtm->rtm_dst_len != 0) {
|
||||
FF_DEBUG("Skipping non-default route #%d (dst_len=%d)", routeCount, rtm->rtm_dst_len);
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_DEBUG("Processing IPv6 default route candidate #%d", routeCount);
|
||||
entry = (__typeof__(entry)) { }; // Default to zero metric (no RTA_PRIORITY found)
|
||||
|
||||
// Parse route attributes
|
||||
size_t rtm_len = RTM_PAYLOAD(nlh);
|
||||
for (struct rtattr* rta = RTM_RTA(rtm);
|
||||
RTA_OK(rta, rtm_len);
|
||||
rta = RTA_NEXT(rta, rtm_len))
|
||||
{
|
||||
switch (rta->rta_type) {
|
||||
case RTA_DST:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
|
||||
FF_MAYBE_UNUSED char str[INET6_ADDRSTRLEN];
|
||||
FF_DEBUG("Unexpected RTA_DST: %s", inet_ntop(AF_INET6, RTA_DATA(rta), str, sizeof(str)));
|
||||
goto next;
|
||||
}
|
||||
break;
|
||||
case RTA_OIF:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) {
|
||||
entry.ifindex = *(uint32_t*) RTA_DATA(rta);
|
||||
FF_DEBUG("Found interface index: %u", entry.ifindex);
|
||||
}
|
||||
break;
|
||||
case RTA_GATEWAY:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(struct in6_addr)) {
|
||||
struct in6_addr* gw = (struct in6_addr*) RTA_DATA(rta);
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(gw)) goto next;
|
||||
FF_MAYBE_UNUSED char str[INET6_ADDRSTRLEN];
|
||||
FF_DEBUG("Found gateway: %s", inet_ntop(AF_INET6, gw, str, sizeof(str)));
|
||||
}
|
||||
break;
|
||||
case RTA_PRIORITY:
|
||||
if (RTA_PAYLOAD(rta) >= sizeof(uint32_t)) {
|
||||
uint32_t metric = *(uint32_t*) RTA_DATA(rta);
|
||||
FF_DEBUG("Found metric: %u", metric);
|
||||
if (metric >= minMetric) goto next;
|
||||
entry.metric = metric;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.ifindex == 0 || entry.metric >= minMetric)
|
||||
{
|
||||
next:
|
||||
FF_DEBUG("Skipping route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
continue;
|
||||
}
|
||||
minMetric = entry.metric;
|
||||
result->ifIndex = entry.ifindex;
|
||||
FF_DEBUG("Updated best route: ifindex=%u, metric=%u", entry.ifindex, entry.metric);
|
||||
|
||||
if (minMetric == 0)
|
||||
{
|
||||
FF_DEBUG("Found zero metric route, stopping further processing");
|
||||
break; // Stop processing if we found a zero metric route
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (minMetric < UINT32_MAX)
|
||||
{
|
||||
if_indextoname(result->ifIndex, result->ifName);
|
||||
FF_DEBUG("Found default IPv6 route: interface=%s, index=%u, metric=%u", result->ifName, result->ifIndex, minMetric);
|
||||
return true;
|
||||
}
|
||||
iface[0] = '\0';
|
||||
FF_DEBUG("No IPv6 default route found");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
{
|
||||
if (getDefaultRouteIPv4(iface, ifIndex))
|
||||
return true;
|
||||
|
||||
return getDefaultRouteIPv6(iface, ifIndex);
|
||||
}
|
||||
|
||||
@@ -4,29 +4,96 @@
|
||||
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
|
||||
#include <iphlpapi.h>
|
||||
|
||||
bool ffNetifGetDefaultRouteImpl(FF_MAYBE_UNUSED char iface[IF_NAMESIZE + 1], uint32_t* ifIndex)
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
DWORD result = GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable);
|
||||
|
||||
if (result != NO_ERROR)
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable)))
|
||||
return false;
|
||||
|
||||
bool foundDefault = false;
|
||||
uint32_t smallestMetric = UINT32_MAX;
|
||||
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
|
||||
{
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if ((row->DestinationPrefix.PrefixLength == 0) &&
|
||||
((row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0) ||
|
||||
(row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr))))
|
||||
if (row->DestinationPrefix.PrefixLength == 0 &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0)
|
||||
{
|
||||
*ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
break;
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp)
|
||||
{
|
||||
MIB_IPINTERFACE_ROW ipInterfaceRow = {
|
||||
.Family = AF_INET,
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
|
||||
uint32_t realMetric = row->Metric /* Metric offset */;
|
||||
|
||||
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow)))
|
||||
realMetric += ipInterfaceRow.Metric /* Interface metric */;
|
||||
|
||||
if (realMetric < smallestMetric)
|
||||
{
|
||||
smallestMetric = realMetric;
|
||||
result->ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeMibTable(pIpForwardTable);
|
||||
|
||||
return foundDefault;
|
||||
}
|
||||
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result)
|
||||
{
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable)))
|
||||
return false;
|
||||
|
||||
bool foundDefault = false;
|
||||
uint32_t smallestMetric = UINT32_MAX;
|
||||
|
||||
for (ULONG i = 0; i < pIpForwardTable->NumEntries; ++i)
|
||||
{
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if (row->DestinationPrefix.PrefixLength == 0 &&
|
||||
row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr))
|
||||
{
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
if (NETIO_SUCCESS(GetIfEntry2(&ifRow)) && ifRow.OperStatus == IfOperStatusUp)
|
||||
{
|
||||
MIB_IPINTERFACE_ROW ipInterfaceRow = {
|
||||
.Family = AF_INET6,
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
};
|
||||
|
||||
uint32_t realMetric = row->Metric /* Metric offset */;
|
||||
|
||||
if (NETIO_SUCCESS(GetIpInterfaceEntry(&ipInterfaceRow)))
|
||||
realMetric += ipInterfaceRow.Metric /* Interface metric */;
|
||||
|
||||
if (realMetric < smallestMetric)
|
||||
{
|
||||
smallestMetric = realMetric;
|
||||
result->ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state)
|
||||
|
||||
if (!state->tfo)
|
||||
{
|
||||
#ifdef __linux__
|
||||
#if __linux__ || __GNU__
|
||||
// Linux doesn't support sendto() on unconnected sockets
|
||||
FF_DEBUG("TCP Fast Open disabled, skipping");
|
||||
return "TCP Fast Open disabled";
|
||||
@@ -34,7 +34,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state)
|
||||
|
||||
#ifndef __APPLE__ // On macOS, TCP_FASTOPEN doesn't seem to be needed
|
||||
// Set TCP Fast Open
|
||||
#ifdef __linux__
|
||||
#if __linux__ || __GNU__
|
||||
int flag = 5; // the queue length of pending packets
|
||||
#else
|
||||
int flag = 1; // enable TCP Fast Open
|
||||
@@ -50,7 +50,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state)
|
||||
FF_DEBUG("Failed to set TCP_FASTOPEN option: %s", strerror(errno));
|
||||
return "setsockopt(TCP_FASTOPEN) failed";
|
||||
} else {
|
||||
#ifdef __linux__
|
||||
#if __linux__ || __GNU__
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN option, queue length: %d", flag);
|
||||
#elif defined(__APPLE__)
|
||||
FF_DEBUG("Successfully set TCP_FASTOPEN_FORCE_ENABLE option");
|
||||
@@ -346,7 +346,7 @@ const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* ho
|
||||
FF_DEBUG("Multithreading mode enabled, creating connection thread");
|
||||
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
|
||||
if (state->thread) {
|
||||
FF_DEBUG("Thread creation successful: thread=%p", (void*)state->thread);
|
||||
FF_DEBUG("Thread creation successful: thread=%p", (void*)(uintptr_t)state->thread);
|
||||
return NULL;
|
||||
}
|
||||
FF_DEBUG("Thread creation failed");
|
||||
|
||||
+2
-49
@@ -28,55 +28,6 @@ const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName)
|
||||
return subKey;
|
||||
}
|
||||
|
||||
bool ffOptionParseModuleArgs(const char* argumentKey, const char* subKey, const char* value, FFModuleArgs* result)
|
||||
{
|
||||
if(ffStrEqualsIgnCase(subKey, "key"))
|
||||
{
|
||||
ffOptionParseString(argumentKey, value, &result->key);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(subKey, "format"))
|
||||
{
|
||||
ffOptionParseString(argumentKey, value, &result->outputFormat);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(subKey, "output-color"))
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <str>\n", argumentKey);
|
||||
exit(477);
|
||||
}
|
||||
ffOptionParseColor(value, &result->outputColor);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrStartsWithIgnCase(subKey, "key-"))
|
||||
{
|
||||
const char* subKey2 = subKey + strlen("key-");
|
||||
if(ffStrEqualsIgnCase(subKey2, "color"))
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <str>\n", argumentKey);
|
||||
exit(477);
|
||||
}
|
||||
ffOptionParseColor(value, &result->keyColor);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(subKey2, "width"))
|
||||
{
|
||||
result->keyWidth = ffOptionParseUInt32(argumentKey, value);
|
||||
return true;
|
||||
}
|
||||
else if(ffStrEqualsIgnCase(subKey2, "icon"))
|
||||
{
|
||||
ffOptionParseString(argumentKey, value, &result->keyIcon);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer)
|
||||
{
|
||||
if(value == NULL)
|
||||
@@ -157,6 +108,8 @@ bool ffOptionParseBoolean(const char* str)
|
||||
|
||||
void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
{
|
||||
if (!value || value[0] == '\0') return;
|
||||
|
||||
// If value is already an ANSI escape code, use it
|
||||
if (value[0] == '\e' && value[1] == '[')
|
||||
{
|
||||
|
||||
+7
-4
@@ -29,10 +29,12 @@ typedef struct FFModuleBaseInfo
|
||||
// This is UB, because `void*` is not compatible with `FF*Options*`.
|
||||
// However we can't do it better unless we move to C++, so that `option` becomes a `this` pointer
|
||||
// https://stackoverflow.com/questions/559581/casting-a-function-pointer-to-another-type
|
||||
bool (*parseCommandOptions)(void* options, const char* key, const char* value);
|
||||
|
||||
void (*initOptions)(void* options);
|
||||
void (*destroyOptions)(void* options);
|
||||
void (*parseJsonObject)(void* options, struct yyjson_val *module);
|
||||
void (*printModule)(void* options);
|
||||
void (*generateJsonResult)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* module);
|
||||
bool (*printModule)(void* options); // true on success
|
||||
bool (*generateJsonResult)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* module); // true on success
|
||||
void (*generateJsonConfig)(void* options, struct yyjson_mut_doc* doc, struct yyjson_mut_val* obj);
|
||||
FFModuleFormatArgList formatArgs;
|
||||
} FFModuleBaseInfo;
|
||||
@@ -63,7 +65,6 @@ typedef struct FFKeyValuePair
|
||||
} FFKeyValuePair;
|
||||
|
||||
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName);
|
||||
bool ffOptionParseModuleArgs(const char* argumentKey, const char* pkey, const char* value, FFModuleArgs* result);
|
||||
void ffOptionParseString(const char* argumentKey, const char* value, FFstrbuf* buffer);
|
||||
FF_C_NODISCARD uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value);
|
||||
FF_C_NODISCARD int32_t ffOptionParseInt32(const char* argumentKey, const char* value);
|
||||
@@ -94,3 +95,5 @@ static inline void ffOptionDestroyModuleArg(FFModuleArgs* args)
|
||||
ffStrbufDestroy(&args->outputFormat);
|
||||
ffStrbufDestroy(&args->outputColor);
|
||||
}
|
||||
|
||||
enum { FF_OPTION_MAX_SIZE = 1 << 8 }; // Maximum size of a single option value, used for static allocation
|
||||
|
||||
+9
-107
@@ -2,7 +2,6 @@
|
||||
#include "common/parsing.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic push
|
||||
@@ -51,63 +50,21 @@ int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2)
|
||||
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty)
|
||||
{
|
||||
if(version->major > 0 || version->minor > 0 || version->patch > 0)
|
||||
ffStrbufAppendF(pretty, "%u", version->major);
|
||||
{
|
||||
ffStrbufAppendUInt(pretty, version->major);
|
||||
}
|
||||
|
||||
if(version->minor > 0 || version->patch > 0)
|
||||
ffStrbufAppendF(pretty, ".%u", version->minor);
|
||||
{
|
||||
ffStrbufAppendC(pretty, '.');
|
||||
ffStrbufAppendUInt(pretty, version->minor);
|
||||
}
|
||||
|
||||
if(version->patch > 0)
|
||||
ffStrbufAppendF(pretty, ".%u", version->patch);
|
||||
}
|
||||
|
||||
static void parseSize(FFstrbuf* result, uint64_t bytes, uint32_t base, const char** prefixes)
|
||||
{
|
||||
double size = (double) bytes;
|
||||
uint8_t counter = 0;
|
||||
|
||||
while(size >= base && counter < instance.config.display.sizeMaxPrefix && prefixes[counter + 1])
|
||||
{
|
||||
size /= base;
|
||||
counter++;
|
||||
ffStrbufAppendC(pretty, '.');
|
||||
ffStrbufAppendUInt(pretty, version->patch);
|
||||
}
|
||||
|
||||
if(counter == 0)
|
||||
ffStrbufAppendF(result, "%" PRIu64 " %s", bytes, prefixes[0]);
|
||||
else
|
||||
ffStrbufAppendF(result, "%.*f %s", instance.config.display.sizeNdigits, size, prefixes[counter]);
|
||||
}
|
||||
|
||||
void ffParseSize(uint64_t bytes, FFstrbuf* result)
|
||||
{
|
||||
switch (instance.config.display.sizeBinaryPrefix)
|
||||
{
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_IEC:
|
||||
parseSize(result, bytes, 1024, (const char*[]) {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL});
|
||||
break;
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_SI:
|
||||
parseSize(result, bytes, 1000, (const char*[]) {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL});
|
||||
break;
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_JEDEC:
|
||||
parseSize(result, bytes, 1024, (const char*[]) {"B", "KB", "MB", "GB", "TB", NULL});
|
||||
break;
|
||||
default:
|
||||
parseSize(result, bytes, 1024, (const char*[]) {"B", NULL});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result)
|
||||
{
|
||||
if (mhz == 0)
|
||||
return false;
|
||||
|
||||
int8_t ndigits = instance.config.display.freqNdigits;
|
||||
|
||||
if (ndigits >= 0)
|
||||
ffStrbufAppendF(result, "%.*f GHz", ndigits, mhz / 1000.);
|
||||
else
|
||||
ffStrbufAppendF(result, "%u MHz", (unsigned) mhz);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
|
||||
@@ -190,61 +147,6 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
}
|
||||
}
|
||||
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
if(totalSeconds < 60)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u second", (unsigned) totalSeconds);
|
||||
if (totalSeconds != 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t seconds = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
if (seconds >= 30)
|
||||
totalSeconds++;
|
||||
|
||||
uint32_t minutes = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
uint32_t hours = (uint32_t) (totalSeconds % 24);
|
||||
totalSeconds /= 24;
|
||||
uint32_t days = (uint32_t) totalSeconds;
|
||||
|
||||
if(days > 0)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u day", days);
|
||||
|
||||
if(days > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
|
||||
if(days >= 100)
|
||||
ffStrbufAppendS(result, "(!)");
|
||||
|
||||
if(hours > 0 || minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
|
||||
if(hours > 0)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u hour", hours);
|
||||
|
||||
if(hours > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
|
||||
if(minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
|
||||
if(minutes > 0)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u min", minutes);
|
||||
|
||||
if(minutes > 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
@@ -24,7 +24,3 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
|
||||
void ffVersionToPretty(const FFVersion* version, FFstrbuf* pretty);
|
||||
int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
|
||||
|
||||
void ffParseSize(uint64_t bytes, FFstrbuf* result);
|
||||
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result);
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result);
|
||||
|
||||
+78
-64
@@ -60,23 +60,32 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
|
||||
uint32_t blocksPercent = (uint32_t) (percent / 100.0 * options->barWidth + 0.5);
|
||||
const bool borderAsValue = options->barBorderLeftElapsed.length && options->barBorderRightElapsed.length;
|
||||
|
||||
uint8_t blocksPercent = (uint8_t) (percent / 100.0 * options->barWidth + 0.5);
|
||||
assert(blocksPercent <= options->barWidth);
|
||||
|
||||
if(options->barBorderLeft.length)
|
||||
if(!borderAsValue && options->barBorderLeft.length)
|
||||
{
|
||||
if(!options->pipe)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
|
||||
if(!options->pipe && options->barColorBorder.length > 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
|
||||
ffStrbufAppend(buffer, &options->barBorderLeft);
|
||||
}
|
||||
|
||||
if (percent != percent)
|
||||
if (percent == -DBL_MAX)
|
||||
{
|
||||
if(!options->pipe)
|
||||
// Use total color for simplification
|
||||
if(!options->pipe && options->barColorTotal.length > 0)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
|
||||
|
||||
for (uint32_t i = 0; i < options->barWidth; ++i)
|
||||
ffStrbufAppend(buffer, &options->barCharElapsed);
|
||||
for (uint8_t i = 0; i < options->barWidth; ++i)
|
||||
{
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeft
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRight
|
||||
: &options->barCharTotal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -85,61 +94,72 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
const char* colorRed = options->percentColorRed.chars;
|
||||
|
||||
FFPercentageTypeFlags percentType = config.type == 0 ? options->percentType : config.type;
|
||||
bool monochrome = !!(percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT);
|
||||
|
||||
for (uint32_t i = 0; i < blocksPercent; ++i)
|
||||
bool autoColorElapsed = ffStrbufIgnCaseEqualS(&options->barColorElapsed, "auto");
|
||||
|
||||
bool monochrome = (percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT) || !autoColorElapsed;
|
||||
if (!options->pipe && options->barColorElapsed.length > 0 && monochrome)
|
||||
{
|
||||
if(!options->pipe)
|
||||
const char* color = NULL;
|
||||
if (!autoColorElapsed)
|
||||
color = options->barColorElapsed.chars;
|
||||
else if (green <= yellow)
|
||||
{
|
||||
if (monochrome)
|
||||
{
|
||||
const char* color = NULL;
|
||||
if (green <= yellow)
|
||||
{
|
||||
if (percent < green) color = colorGreen;
|
||||
else if (percent < yellow) color = colorYellow;
|
||||
else color = colorRed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (percent < yellow) color = colorRed;
|
||||
else if (percent < green) color = colorYellow;
|
||||
else color = colorGreen;
|
||||
}
|
||||
ffStrbufAppendF(buffer, "\e[%sm", color);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
if (i == section2Begin)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed));
|
||||
else if (i == section1Begin)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else if (i == 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed));
|
||||
}
|
||||
if (percent < green) color = colorGreen;
|
||||
else if (percent < yellow) color = colorYellow;
|
||||
else color = colorRed;
|
||||
}
|
||||
ffStrbufAppend(buffer, &options->barCharElapsed);
|
||||
else
|
||||
{
|
||||
if (percent < yellow) color = colorRed;
|
||||
else if (percent < green) color = colorYellow;
|
||||
else color = colorGreen;
|
||||
}
|
||||
ffStrbufAppendF(buffer, "\e[%sm", color);
|
||||
}
|
||||
for (uint8_t i = 0; i < blocksPercent; ++i)
|
||||
{
|
||||
if (!options->pipe && options->barColorElapsed.length > 0 && !monochrome)
|
||||
{
|
||||
uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
|
||||
if (i == section2Begin)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed));
|
||||
else if (i == section1Begin)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else if (i == 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed));
|
||||
}
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeftElapsed
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRightElapsed
|
||||
: &options->barCharElapsed);
|
||||
}
|
||||
|
||||
if (blocksPercent < options->barWidth)
|
||||
{
|
||||
if(!options->pipe)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
|
||||
for (uint32_t i = blocksPercent; i < options->barWidth; ++i)
|
||||
ffStrbufAppend(buffer, &options->barCharTotal);
|
||||
if(!options->pipe && options->barColorTotal.length > 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorTotal.chars);
|
||||
for (uint8_t i = blocksPercent; i < options->barWidth; ++i)
|
||||
{
|
||||
ffStrbufAppend(buffer, borderAsValue && i == 0
|
||||
? &options->barBorderLeft
|
||||
: borderAsValue && i == options->barWidth - 1
|
||||
? &options->barBorderRight
|
||||
: &options->barCharTotal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(options->barBorderRight.length)
|
||||
if(!borderAsValue && options->barBorderRight.length)
|
||||
{
|
||||
if(!options->pipe)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
|
||||
if(!options->pipe && options->barColorBorder.length > 0)
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
|
||||
ffStrbufAppend(buffer, &options->barBorderRight);
|
||||
}
|
||||
|
||||
if(!options->pipe)
|
||||
if(!options->pipe && (options->barColorElapsed.length > 0 || options->barColorTotal.length > 0 || options->barColorBorder.length > 0))
|
||||
{
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
appendOutputColor(buffer, module);
|
||||
@@ -165,7 +185,7 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
const char* colorYellow = options->percentColorYellow.chars;
|
||||
const char* colorRed = options->percentColorRed.chars;
|
||||
|
||||
if(percent != percent)
|
||||
if(percent == -DBL_MAX)
|
||||
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
|
||||
else if(green <= yellow)
|
||||
{
|
||||
@@ -175,7 +195,6 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
|
||||
else
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -187,7 +206,8 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
|
||||
}
|
||||
}
|
||||
ffStrbufAppendF(buffer, "%.*f%%", options->percentNdigits, percent);
|
||||
ffStrbufAppendF(buffer, "%*.*f%s%%", options->percentWidth, options->percentNdigits, percent,
|
||||
options->percentSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
|
||||
if (colored && !options->pipe)
|
||||
{
|
||||
@@ -239,14 +259,14 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageModuleConfig* config)
|
||||
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config)
|
||||
{
|
||||
if (!ffStrEqualsIgnCase(key, "percent"))
|
||||
if (!unsafe_yyjson_equals_str(key, "percent"))
|
||||
return false;
|
||||
|
||||
if (!yyjson_is_obj(value))
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s must be an object\n", key);
|
||||
fprintf(stderr, "Error: usage: %s must be an object\n", unsafe_yyjson_get_str(key));
|
||||
exit(480);
|
||||
}
|
||||
|
||||
@@ -288,16 +308,10 @@ bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageMo
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig defaultConfig, FFPercentageModuleConfig config)
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config)
|
||||
{
|
||||
if (config.green == defaultConfig.green && config.yellow == defaultConfig.yellow)
|
||||
return;
|
||||
|
||||
yyjson_mut_val* percent = yyjson_mut_obj_add_obj(doc, module, "percent");
|
||||
if (config.green != defaultConfig.green)
|
||||
yyjson_mut_obj_add_uint(doc, percent, "green", config.green);
|
||||
if (config.yellow != defaultConfig.yellow)
|
||||
yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow);
|
||||
if (config.type != defaultConfig.type)
|
||||
yyjson_mut_obj_add_uint(doc, percent, "type", config.type);
|
||||
yyjson_mut_obj_add_uint(doc, percent, "green", config.green);
|
||||
yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow);
|
||||
yyjson_mut_obj_add_uint(doc, percent, "type", config.type);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ typedef enum __attribute__((__packed__)) FFPercentageTypeFlags
|
||||
FF_PERCENTAGE_TYPE_BAR_BIT = 1 << 1,
|
||||
FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT = 1 << 2,
|
||||
FF_PERCENTAGE_TYPE_NUM_COLOR_BIT = 1 << 3,
|
||||
FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT = FF_PERCENTAGE_TYPE_NUM_COLOR_BIT,
|
||||
FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT = 1 << 4,
|
||||
FF_PERCENTAGE_TYPE_FORCE_UNSIGNED_ = UINT8_MAX,
|
||||
} FFPercentageTypeFlags;
|
||||
static_assert(sizeof(FFPercentageTypeFlags) == 1, "");
|
||||
@@ -40,6 +40,6 @@ typedef struct yyjson_val yyjson_val;
|
||||
typedef struct yyjson_mut_doc yyjson_mut_doc;
|
||||
typedef struct yyjson_mut_val yyjson_mut_val;
|
||||
bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentageModuleConfig* config);
|
||||
bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentageModuleConfig* config);
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig defaultConfig, FFPercentageModuleConfig config);
|
||||
bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config);
|
||||
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentageModuleConfig config);
|
||||
const char* ffPercentParseTypeJsonConfig(yyjson_val* value, FFPercentageTypeFlags* result);
|
||||
|
||||
@@ -234,15 +234,42 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
|
||||
assert(processName->length > 0);
|
||||
ffStrbufClear(exe);
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) || defined(__GNU__)
|
||||
|
||||
char filePath[64];
|
||||
snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int)pid);
|
||||
|
||||
if(ffReadFileBuffer(filePath, exe))
|
||||
{
|
||||
ffStrbufRecalculateLength(exe); //Trim the arguments
|
||||
ffStrbufTrimRightSpace(exe);
|
||||
const char* p = exe->chars;
|
||||
uint32_t len = (uint32_t) strlen(p);
|
||||
|
||||
if (len + 1 < exe->length)
|
||||
{
|
||||
const char* name = memrchr(p, '/', len);
|
||||
if (name) name++; else name = p;
|
||||
|
||||
// For interpreters, try to find the real script path in the arguments
|
||||
if (ffStrStartsWith(name, "python")
|
||||
#ifndef __ANDROID__
|
||||
|| ffStrEquals(name, "guile") // for shepherd
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// `cmdline` always ends with a trailing '\0', and ffReadFileBuffer appends another \0
|
||||
// So `exe->chars` is always double '\0' terminated
|
||||
for (p = p + len + 1; *p && *p == '-'; p += strlen(p) + 1) // Skip arguments
|
||||
assert(p - exe->chars < exe->allocated);
|
||||
if (*p)
|
||||
{
|
||||
len = (uint32_t) strlen(p);
|
||||
memmove(exe->chars, p, len + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(len < exe->allocated);
|
||||
exe->length = len;
|
||||
ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash
|
||||
}
|
||||
|
||||
@@ -436,33 +463,53 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
|
||||
if (pid <= 0)
|
||||
return "Invalid pid";
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__) || defined(__GNU__)
|
||||
|
||||
char procFilePath[64];
|
||||
if (ppid)
|
||||
#if __linux__
|
||||
if (ppid || tty)
|
||||
#endif
|
||||
{
|
||||
snprintf(procFilePath, sizeof(procFilePath), "/proc/%d/stat", (int)pid);
|
||||
char buf[PROC_FILE_BUFFSIZ];
|
||||
ssize_t nRead = ffReadFileData(procFilePath, sizeof(buf) - 1, buf);
|
||||
if(nRead <= 8)
|
||||
return "ffReadFileData(/proc/pid/stat, PROC_FILE_BUFFSIZ-1, buf) failed";
|
||||
buf[nRead] = '\0';
|
||||
buf[nRead] = '\0'; // pid (comm) state ppid pgrp session tty
|
||||
|
||||
*ppid = 0;
|
||||
static_assert(sizeof(*ppid) == sizeof(int), "");
|
||||
const char* pState = NULL;
|
||||
|
||||
ffStrbufEnsureFixedLengthFree(name, 255);
|
||||
int tty_;
|
||||
if(
|
||||
sscanf(buf, "%*s (%255[^)]) %*c %d %*d %*d %d", name->chars, ppid, &tty_) < 2 || //stat (comm) state ppid pgrp session tty
|
||||
name->chars[0] == '\0'
|
||||
)
|
||||
return "sscanf(stat) failed";
|
||||
{
|
||||
// comm in `/proc/pid/stat` is not encoded, and may contain ' ', ')' or even `\n`
|
||||
const char* start = memchr(buf, '(', (size_t) nRead);
|
||||
if (!start)
|
||||
return "memchr(stat, '(') failed";
|
||||
start++;
|
||||
const char* end = memrchr(start, ')', (size_t) nRead - (size_t) (start - buf));
|
||||
if (!end)
|
||||
return "memrchr(stat, ')') failed";
|
||||
ffStrbufSetNS(name, (uint32_t) (end - start), start);
|
||||
ffStrbufTrimRightSpace(name);
|
||||
if (name->chars[0] == '\0')
|
||||
return "process name is empty";
|
||||
pState = end + 2; // skip ") "
|
||||
}
|
||||
|
||||
ffStrbufRecalculateLength(name);
|
||||
if (tty)
|
||||
*tty = tty_ & 0xFF;
|
||||
#if !__linux__
|
||||
if (ppid || tty)
|
||||
#endif
|
||||
{
|
||||
int ppid_, tty_;
|
||||
if(sscanf(pState + 2, "%d %*d %*d %d", &ppid_, &tty_) < 2)
|
||||
return "sscanf(stat) failed";
|
||||
|
||||
if (ppid)
|
||||
*ppid = (pid_t) ppid_;
|
||||
if (tty)
|
||||
*tty = tty_ & 0xFF;
|
||||
}
|
||||
}
|
||||
#if __linux__
|
||||
else
|
||||
{
|
||||
snprintf(procFilePath, sizeof(procFilePath), "/proc/%d/comm", (int)pid);
|
||||
@@ -471,6 +518,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
|
||||
return "ffReadFileBuffer(/proc/pid/comm, name) failed";
|
||||
ffStrbufTrimRightSpace(name);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "size.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
static void appendNum(FFstrbuf* result, uint64_t bytes, uint32_t base, const char** prefixes)
|
||||
{
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
double size = (double) bytes;
|
||||
uint8_t counter = 0;
|
||||
|
||||
while(size >= base && counter < options->sizeMaxPrefix && prefixes[counter + 1])
|
||||
{
|
||||
size /= base;
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (counter == 0)
|
||||
ffStrbufAppendUInt(result, bytes);
|
||||
else
|
||||
ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits);
|
||||
if (options->sizeSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER)
|
||||
ffStrbufAppendC(result, ' ');
|
||||
ffStrbufAppendS(result, prefixes[counter]);
|
||||
}
|
||||
|
||||
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result)
|
||||
{
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
switch (options->sizeBinaryPrefix)
|
||||
{
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_IEC:
|
||||
appendNum(result, bytes, 1024, (const char*[]) {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", NULL});
|
||||
break;
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_SI:
|
||||
appendNum(result, bytes, 1000, (const char*[]) {"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", NULL});
|
||||
break;
|
||||
case FF_SIZE_BINARY_PREFIX_TYPE_JEDEC:
|
||||
appendNum(result, bytes, 1024, (const char*[]) {"B", "KB", "MB", "GB", "TB", NULL});
|
||||
break;
|
||||
default:
|
||||
appendNum(result, bytes, 1024, (const char*[]) {"B", NULL});
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
void ffSizeAppendNum(uint64_t bytes, FFstrbuf* result);
|
||||
+15
-21
@@ -5,7 +5,7 @@
|
||||
|
||||
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module)
|
||||
{
|
||||
if (celsius != celsius) // ignores NaN
|
||||
if (celsius == -DBL_MAX) // ignores invalid value
|
||||
return;
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
@@ -41,13 +41,16 @@ void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig confi
|
||||
{
|
||||
case FF_TEMPERATURE_UNIT_DEFAULT:
|
||||
case FF_TEMPERATURE_UNIT_CELSIUS:
|
||||
ffStrbufAppendF(buffer, "%.*f°C", options->tempNdigits, celsius);
|
||||
ffStrbufAppendF(buffer, "%.*f%s°C", options->tempNdigits, celsius,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
break;
|
||||
case FF_TEMPERATURE_UNIT_FAHRENHEIT:
|
||||
ffStrbufAppendF(buffer, "%.*f°F", options->tempNdigits, celsius * 1.8 + 32);
|
||||
ffStrbufAppendF(buffer, "%.*f%s°F", options->tempNdigits, celsius * 1.8 + 32,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
break;
|
||||
case FF_TEMPERATURE_UNIT_KELVIN:
|
||||
ffStrbufAppendF(buffer, "%.*f K", options->tempNdigits, celsius + 273.15);
|
||||
ffStrbufAppendF(buffer, "%.*f%sK", options->tempNdigits, celsius + 273.15,
|
||||
options->tempSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -104,9 +107,9 @@ bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char*
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config)
|
||||
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config)
|
||||
{
|
||||
if (!ffStrEqualsIgnCase(key, "temp"))
|
||||
if (!unsafe_yyjson_equals_str(key, "temp"))
|
||||
return false;
|
||||
|
||||
if (yyjson_is_bool(value))
|
||||
@@ -123,7 +126,7 @@ bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, F
|
||||
|
||||
if (!yyjson_is_obj(value))
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s must be an object or a boolean\n", key);
|
||||
fprintf(stderr, "Error: usage: %s must be an object or a boolean\n", unsafe_yyjson_get_str(key));
|
||||
exit(480);
|
||||
}
|
||||
|
||||
@@ -156,23 +159,14 @@ bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, F
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FF_MAYBE_UNUSED bool defaultTemp, FFColorRangeConfig defaultConfig, bool temp, FFColorRangeConfig config)
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config)
|
||||
{
|
||||
assert(defaultTemp == false); // assume defaultTemp is always false
|
||||
|
||||
if (!temp)
|
||||
return;
|
||||
|
||||
if (config.green != defaultConfig.green || config.yellow != defaultConfig.yellow)
|
||||
{
|
||||
yyjson_mut_val* temp = yyjson_mut_obj_add_obj(doc, module, "temp");
|
||||
if (config.green != defaultConfig.green)
|
||||
yyjson_mut_obj_add_uint(doc, temp, "green", config.green);
|
||||
if (config.yellow != defaultConfig.yellow)
|
||||
yyjson_mut_obj_add_uint(doc, temp, "yellow", config.yellow);
|
||||
}
|
||||
yyjson_mut_obj_add_bool(doc, module, "temp", false);
|
||||
else
|
||||
{
|
||||
yyjson_mut_obj_add_bool(doc, module, "temp", true);
|
||||
yyjson_mut_val* temp = yyjson_mut_obj_add_obj(doc, module, "temp");
|
||||
yyjson_mut_obj_add_uint(doc, temp, "green", config.green);
|
||||
yyjson_mut_obj_add_uint(doc, temp, "yellow", config.yellow);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -5,5 +5,5 @@
|
||||
|
||||
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module);
|
||||
bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* value, bool* useTemp, FFColorRangeConfig* config);
|
||||
bool ffTempsParseJsonObject(const char* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config);
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FF_MAYBE_UNUSED bool defaultTemp, FFColorRangeConfig defaultConfig, bool temp, FFColorRangeConfig config);
|
||||
bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config);
|
||||
void ffTempsGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, bool temp, FFColorRangeConfig config);
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#include <time.h>
|
||||
|
||||
char ffTimeInternalBuffer[64]; // Reduce memory usage and prevent redundant allocations
|
||||
+15
-12
@@ -11,6 +11,8 @@
|
||||
#include <OS.h>
|
||||
#endif
|
||||
|
||||
#include "util/arrayUtils.h"
|
||||
|
||||
static inline double ffTimeGetTick(void) //In msec
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -64,11 +66,12 @@ static inline const char* ffTimeToFullStr(uint64_t msec)
|
||||
time_t tsec = (time_t) (msec / 1000);
|
||||
const struct tm* tm = localtime(&tsec);
|
||||
|
||||
static char buf[32];
|
||||
strftime(buf, __builtin_strlen("0000-00-00T00:00:00") + 1, "%FT%T", tm);
|
||||
snprintf(buf + __builtin_strlen("0000-00-00T00:00:00"), __builtin_strlen(".000") + 1, ".%03u", (unsigned) (msec % 1000));
|
||||
strftime(buf + __builtin_strlen("0000-00-00T00:00:00.000"), __builtin_strlen("+0000") + 1, "%z", tm);
|
||||
return buf;
|
||||
extern char ffTimeInternalBuffer[64];
|
||||
uint32_t len = 0;
|
||||
len += (uint32_t) strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer) - len, "%FT%T", tm);
|
||||
len += (uint32_t) snprintf(ffTimeInternalBuffer + len, ARRAY_SIZE(ffTimeInternalBuffer) - len, ".%03u", (unsigned) (msec % 1000));
|
||||
len += (uint32_t) strftime(ffTimeInternalBuffer + len, ARRAY_SIZE(ffTimeInternalBuffer) - len, "%z", tm);
|
||||
return ffTimeInternalBuffer;
|
||||
}
|
||||
|
||||
// Not thread-safe
|
||||
@@ -77,9 +80,9 @@ static inline const char* ffTimeToShortStr(uint64_t msec)
|
||||
if (msec == 0) return "";
|
||||
time_t tsec = (time_t) (msec / 1000);
|
||||
|
||||
static char buf[32];
|
||||
strftime(buf, sizeof(buf), "%F %T", localtime(&tsec));
|
||||
return buf;
|
||||
extern char ffTimeInternalBuffer[64];
|
||||
strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer), "%F %T", localtime(&tsec));
|
||||
return ffTimeInternalBuffer;
|
||||
}
|
||||
|
||||
// Not thread-safe
|
||||
@@ -88,10 +91,10 @@ static inline const char* ffTimeToTimeStr(uint64_t msec)
|
||||
if (msec == 0) return "";
|
||||
time_t tsec = (time_t) (msec / 1000);
|
||||
|
||||
static char buf[32];
|
||||
strftime(buf, sizeof(buf), "%T", localtime(&tsec));
|
||||
sprintf(buf + __builtin_strlen("00:00:00"), ".%03u", (unsigned) (msec % 1000));
|
||||
return buf;
|
||||
extern char ffTimeInternalBuffer[64];
|
||||
uint32_t len = (uint32_t) strftime(ffTimeInternalBuffer, ARRAY_SIZE(ffTimeInternalBuffer), "%T", localtime(&tsec));
|
||||
sprintf(ffTimeInternalBuffer + len, ".%03u", (unsigned) (msec % 1000));
|
||||
return ffTimeInternalBuffer;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
+126
-897
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/battery/option.h"
|
||||
|
||||
#define FF_BATTERY_TEMP_UNSET (0/0.0)
|
||||
#define FF_BATTERY_TEMP_UNSET (-DBL_MAX)
|
||||
|
||||
typedef struct FFBatteryResult
|
||||
{
|
||||
@@ -15,7 +16,7 @@ typedef struct FFBatteryResult
|
||||
double capacity;
|
||||
double temperature;
|
||||
uint32_t cycleCount;
|
||||
int32_t timeRemaining;
|
||||
int32_t timeRemaining; // in seconds, -1 if unknown
|
||||
} FFBatteryResult;
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results);
|
||||
|
||||
@@ -96,6 +96,7 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
battery->cycleCount = 0;
|
||||
battery->timeRemaining = -1;
|
||||
battery->capacity = 0;
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->status);
|
||||
@@ -124,11 +125,11 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
double level = 0, scale = 0;
|
||||
if (ffParsePropLines(start, "level: ", &temp))
|
||||
level = ffStrbufToDouble(&temp);
|
||||
level = ffStrbufToDouble(&temp, -DBL_MAX);
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
if (ffParsePropLines(start, "scale: ", &temp))
|
||||
scale = ffStrbufToDouble(&temp);
|
||||
scale = ffStrbufToDouble(&temp, -DBL_MAX);
|
||||
ffStrbufClear(&temp);
|
||||
|
||||
if (level > 0 && scale > 0)
|
||||
@@ -138,7 +139,11 @@ static const char* parseDumpsys(FFBatteryOptions* options, FFlist* results)
|
||||
if(options->temp)
|
||||
{
|
||||
if (ffParsePropLines(start, "temperature: ", &temp))
|
||||
battery->temperature = ffStrbufToDouble(&temp);
|
||||
{
|
||||
battery->temperature = ffStrbufToDouble(&temp, FF_BATTERY_TEMP_UNSET);
|
||||
if (battery->temperature != FF_BATTERY_TEMP_UNSET)
|
||||
battery->temperature /= 10.0; // Android returns temperature in tenths of a degree
|
||||
}
|
||||
ffStrbufClear(&temp);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFl
|
||||
return;
|
||||
|
||||
FFBatteryResult* result = ffListAdd(results);
|
||||
result->capacity = ffStrbufToDouble(&tmpBuffer);
|
||||
result->capacity = ffStrbufToDouble(&tmpBuffer, 0);
|
||||
|
||||
//At this point, we have a battery. Try to get as much values as possible.
|
||||
|
||||
@@ -154,7 +154,11 @@ static void parseBattery(int dfd, const char* id, FFBatteryOptions* options, FFl
|
||||
if (options->temp)
|
||||
{
|
||||
if (ffReadFileBufferRelative(dfd, "temp", &tmpBuffer))
|
||||
result->temperature = ffStrbufToDouble(&tmpBuffer) / 10;
|
||||
{
|
||||
result->temperature = ffStrbufToDouble(&tmpBuffer, FF_BATTERY_TEMP_UNSET);
|
||||
if (result->temperature != FF_BATTERY_TEMP_UNSET)
|
||||
result->temperature /= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results)
|
||||
|
||||
battery->cycleCount = bi.CycleCount;
|
||||
|
||||
battery->temperature = 0.0/0.0;
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
if(options->temp)
|
||||
{
|
||||
bqi.InformationLevel = BatteryTemperature;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bios/option.h"
|
||||
|
||||
typedef struct FFBiosResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bluetooth/option.h"
|
||||
|
||||
typedef struct FFBluetoothResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bluetoothradio/option.h"
|
||||
|
||||
typedef struct FFBluetoothRadioResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/board/option.h"
|
||||
|
||||
typedef struct FFBoardResult
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bootmgr/option.h"
|
||||
|
||||
typedef struct FFBootmgrResult
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "util/FFlist.h"
|
||||
#include "modules/brightness/option.h"
|
||||
|
||||
typedef struct FFBrightnessResult
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@ static const char* detectWithBacklight(FFlist* result)
|
||||
ffStrbufAppendS(&backlightDir, "/brightness");
|
||||
if(ffReadFileBuffer(backlightDir.chars, &buffer))
|
||||
{
|
||||
double actualBrightness = ffStrbufToDouble(&buffer);
|
||||
double actualBrightness = ffStrbufToDouble(&buffer, 0);
|
||||
ffStrbufSubstrBefore(&backlightDir, backlightDirLength);
|
||||
ffStrbufAppendS(&backlightDir, entry->d_name);
|
||||
ffStrbufAppendS(&backlightDir, "/max_brightness");
|
||||
@@ -71,7 +71,7 @@ static const char* detectWithBacklight(FFlist* result)
|
||||
}
|
||||
else
|
||||
ffStrbufInitS(&brightness->name, entry->d_name);
|
||||
brightness->max = ffStrbufToDouble(&buffer);
|
||||
brightness->max = ffStrbufToDouble(&buffer, 0);
|
||||
brightness->min = 0;
|
||||
brightness->current = actualBrightness;
|
||||
brightness->builtin = true;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/btrfs/option.h"
|
||||
|
||||
typedef struct FFBtrfsDiskUsage
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/camera/option.h"
|
||||
|
||||
typedef struct FFCameraResult
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@ const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
|
||||
ffStrbufInitStatic(&camera->name, "Unknown");
|
||||
}
|
||||
ffStrbufInit(&camera->vendor);
|
||||
ffStrbufInitS(&camera->id, yyjson_get_str(yyjson_obj_get(device, "id")));
|
||||
ffStrbufInitJsonVal(&camera->id, yyjson_obj_get(device, "id"));
|
||||
yyjson_val* sizes = yyjson_arr_get_first(yyjson_obj_get(device, "jpeg_output_sizes"));
|
||||
if (yyjson_is_obj(sizes))
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/chassis/option.h"
|
||||
|
||||
typedef struct FFChassisResult
|
||||
{
|
||||
|
||||
@@ -60,3 +60,490 @@ const char* ffCPUQualcommCodeToName(uint32_t code)
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
|
||||
#include <cpuid.h>
|
||||
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
||||
if (__get_cpuid(0x16, &eax, &ebx, &ecx, &edx))
|
||||
{
|
||||
// WARNING: CPUID may report frequencies of efficient cores
|
||||
// cpuid returns 0 MHz when hypervisor is enabled
|
||||
if (eax) cpu->frequencyBase = eax;
|
||||
if (ebx) cpu->frequencyMax = ebx;
|
||||
}
|
||||
|
||||
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx))
|
||||
{
|
||||
// Feature tests (leaf1.ecx, leaf7.ebx)
|
||||
bool sse2 = (ecx & bit_SSE2) != 0;
|
||||
bool sse4_2 = (ecx & bit_SSE4_2) != 0;
|
||||
bool pclmul = (ecx & bit_PCLMUL) != 0;
|
||||
bool popcnt = (ecx & bit_POPCNT) != 0;
|
||||
bool fma = (ecx & bit_FMA) != 0;
|
||||
bool osxsave = (ecx & bit_OSXSAVE) != 0;
|
||||
|
||||
unsigned int eax7 = 0, ebx7 = 0, ecx7 = 0, edx7 = 0;
|
||||
__get_cpuid_count(7, 0, &eax7, &ebx7, &ecx7, &edx7);
|
||||
|
||||
bool avx2 = (ebx7 & bit_AVX2) != 0;
|
||||
bool bmi2 = (ebx7 & bit_BMI2) != 0;
|
||||
bool avx512f = (ebx7 & bit_AVX512F) != 0;
|
||||
bool avx512bw = (ebx7 & bit_AVX512BW) != 0;
|
||||
bool avx512dq = (ebx7 & bit_AVX512DQ) != 0;
|
||||
|
||||
// OS support for AVX/AVX512: check XGETBV (requires OSXSAVE)
|
||||
bool avx_os = false;
|
||||
bool avx512_os = false;
|
||||
if (osxsave)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
"xgetbv"
|
||||
: "=a"(eax), "=d"(edx)
|
||||
: "c"(0)
|
||||
:
|
||||
);
|
||||
uint64_t xcr0 = ((uint64_t)edx << 32) | eax;
|
||||
|
||||
// AVX requires XCR0[1:2] == 11b (XMM and YMM state)
|
||||
avx_os = (xcr0 & 0x6ULL) == 0x6ULL;
|
||||
// AVX512 requires XCR0[7,5,6] etc. common mask 0xE6 (bits 1,2,5,6,7)
|
||||
avx512_os = (xcr0 & 0xE6ULL) == 0xE6ULL;
|
||||
}
|
||||
|
||||
cpu->march = "unknown";
|
||||
if (avx512f && avx512bw && avx512dq && avx512_os) cpu->march = "x86_64-v4";
|
||||
else if (avx2 && fma && bmi2 && avx_os) cpu->march = "x86_64-v3";
|
||||
else if (sse4_2 && popcnt && pclmul) cpu->march = "x86_64-v2";
|
||||
else if (sse2) cpu->march = "x86_64-v1";
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
// This is not accurate because a lot of flags are optional from old versions
|
||||
// https://developer.arm.com/documentation/109697/2025_06/Feature-descriptions?lang=en
|
||||
// https://en.wikipedia.org/wiki/AArch64#ARM-A_(application_architecture)
|
||||
// Worth noting: Apple M1 is marked as ARMv8.5-A on Wikipedia, but it lacks BTI (mandatory in v8.5)
|
||||
|
||||
#ifdef __linux__
|
||||
#include "common/io/io.h"
|
||||
#include <elf.h>
|
||||
#include <asm/hwcap.h>
|
||||
|
||||
#ifndef HWCAP2_SME
|
||||
#define HWCAP2_SME (1UL << 23)
|
||||
#endif
|
||||
#ifndef HWCAP2_SME2
|
||||
#define HWCAP2_SME2 (1UL << 37)
|
||||
#endif
|
||||
#ifndef HWCAP2_CSSC
|
||||
#define HWCAP2_CSSC (1UL << 34)
|
||||
#endif
|
||||
#ifndef HWCAP2_SME2P1
|
||||
#define HWCAP2_SME2P1 (1UL << 38)
|
||||
#endif
|
||||
#ifndef HWCAP2_MOPS
|
||||
#define HWCAP2_MOPS (1UL << 43)
|
||||
#endif
|
||||
#ifndef HWCAP2_F8E4M3
|
||||
#define HWCAP2_F8E4M3 (1UL << 55)
|
||||
#endif
|
||||
#ifndef HWCAP2_F8E5M2
|
||||
#define HWCAP2_F8E5M2 (1UL << 56)
|
||||
#endif
|
||||
#ifndef HWCAP_CMPBR
|
||||
#define HWCAP_CMPBR (1UL << 33)
|
||||
#endif
|
||||
#ifndef HWCAP_FPRCVT
|
||||
#define HWCAP_FPRCVT (1UL << 34)
|
||||
#endif
|
||||
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
char buf[PROC_FILE_BUFFSIZ];
|
||||
ssize_t nRead = ffReadFileData("/proc/self/auxv", ARRAY_SIZE(buf), buf);
|
||||
|
||||
if (nRead < (ssize_t) sizeof(Elf64_auxv_t)) return;
|
||||
|
||||
uint64_t hwcap = 0, hwcap2 = 0;
|
||||
|
||||
for (Elf64_auxv_t* auxv = (Elf64_auxv_t*)buf; (char*)auxv < buf + nRead; ++auxv)
|
||||
{
|
||||
if (auxv->a_type == AT_HWCAP)
|
||||
{
|
||||
hwcap = auxv->a_un.a_val;
|
||||
}
|
||||
else if (auxv->a_type == AT_HWCAP2)
|
||||
{
|
||||
hwcap2 = auxv->a_un.a_val;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hwcap) return;
|
||||
|
||||
cpu->march = "unknown";
|
||||
|
||||
// ARMv8-A
|
||||
bool has_fp = (hwcap & HWCAP_FP) != 0;
|
||||
bool has_asimd = (hwcap & HWCAP_ASIMD) != 0;
|
||||
|
||||
// ARMv8.1-A
|
||||
bool has_atomics = (hwcap & HWCAP_ATOMICS) != 0; // optional from v8.0
|
||||
bool has_crc32 = (hwcap & HWCAP_CRC32) != 0; // optional from v8.0
|
||||
bool has_asimdrdm = (hwcap & HWCAP_ASIMDRDM) != 0; // optional from v8.0
|
||||
|
||||
// ARMv8.2-A
|
||||
bool has_fphp = (hwcap & HWCAP_FPHP) != 0; // optional
|
||||
bool has_dcpop = (hwcap & HWCAP_DCPOP) != 0; // DC CVAP, optional from v8.1
|
||||
|
||||
// ARMv8.3-A
|
||||
bool has_paca = (hwcap & HWCAP_PACA) != 0; // optional from v8.2
|
||||
bool has_lrcpc = (hwcap & HWCAP_LRCPC) != 0; // optional from v8.2
|
||||
bool has_fcma = (hwcap & HWCAP_FCMA) != 0; // optional from v8.2
|
||||
bool has_jscvt = (hwcap & HWCAP_JSCVT) != 0; // optional from v8.2
|
||||
|
||||
// ARMv8.4-A
|
||||
bool has_dit = (hwcap & HWCAP_DIT) != 0; // optional from v8.3
|
||||
bool has_flagm = (hwcap & HWCAP_FLAGM) != 0; // optional from v8.1
|
||||
bool has_ilrcpc = (hwcap & HWCAP_ILRCPC) != 0; // optional from v8.2
|
||||
|
||||
// ARMv8.5-A
|
||||
bool has_bti = (hwcap2 & HWCAP2_BTI) != 0; // optional from v8.4
|
||||
bool has_sb = (hwcap & HWCAP_SB) != 0; // optional from v8.0
|
||||
bool has_dcpodp = (hwcap2 & HWCAP2_DCPODP) != 0; // optional from v8.1
|
||||
bool has_flagm2 = (hwcap2 & HWCAP2_FLAGM2) != 0; // optional from v8.4
|
||||
bool has_frint = (hwcap2 & HWCAP2_FRINT) != 0; // optional from v8.4
|
||||
|
||||
// ARMv9.0-A
|
||||
bool has_sve2 = (hwcap2 & HWCAP2_SVE2) != 0;
|
||||
|
||||
// ARMv9.1-A
|
||||
// ARMv8.6-A
|
||||
bool has_bf16 = (hwcap2 & HWCAP2_BF16) != 0; // optional from v8.2
|
||||
bool has_i8mm = (hwcap2 & HWCAP2_I8MM) != 0; // optional from v8.1
|
||||
|
||||
// ARMv8.7-A
|
||||
bool has_afp = (hwcap2 & HWCAP2_AFP) != 0; // optional from v8.6
|
||||
|
||||
// ARMv9.2-A
|
||||
bool has_sme = (hwcap2 & HWCAP2_SME) != 0;
|
||||
|
||||
// ARMv9.3-A
|
||||
bool has_sme2 = (hwcap2 & HWCAP2_SME2) != 0; // optional from v9.2
|
||||
|
||||
// ARMv8.8-A
|
||||
bool has_mops = (hwcap2 & HWCAP2_MOPS) != 0; // optional from v8.7
|
||||
|
||||
// ARMv8.9-A
|
||||
bool has_cssc = (hwcap2 & HWCAP2_CSSC) != 0; // optional from v8.7
|
||||
|
||||
// ARMv9.4-A
|
||||
bool has_sme2p1 = (hwcap2 & HWCAP2_SME2P1) != 0; // optional from v9.2
|
||||
|
||||
// ARMv9.5-A
|
||||
bool has_f8e4m3 = (hwcap2 & HWCAP2_F8E4M3) != 0; // optional from v9.2
|
||||
bool has_f8e5m2 = (hwcap2 & HWCAP2_F8E5M2) != 0; // optional from v9.2
|
||||
|
||||
// ARMv9.6-A
|
||||
bool has_cmpbr = (hwcap & HWCAP_CMPBR) != 0; // optional from v9.5
|
||||
bool has_fprcvt = (hwcap & HWCAP_FPRCVT) != 0; // optional from v9.5
|
||||
|
||||
if (has_sve2 || has_sme) {
|
||||
// ARMv9
|
||||
if (has_cmpbr && has_fprcvt) {
|
||||
cpu->march = "ARMv9.6-A";
|
||||
} else if (has_f8e5m2 && has_f8e4m3) {
|
||||
cpu->march = "ARMv9.5-A";
|
||||
} else if (has_sme2p1) {
|
||||
cpu->march = "ARMv9.4-A";
|
||||
} else if (has_sme2) {
|
||||
cpu->march = "ARMv9.3-A";
|
||||
} else if (has_sme) {
|
||||
cpu->march = "ARMv9.2-A";
|
||||
} else if (has_i8mm && has_bf16) {
|
||||
cpu->march = "ARMv9.1-A";
|
||||
} else {
|
||||
cpu->march = "ARMv9.0-A";
|
||||
}
|
||||
} else {
|
||||
// ARMv8
|
||||
if (has_cssc) {
|
||||
cpu->march = "ARMv8.9-A";
|
||||
} else if (has_mops) {
|
||||
cpu->march = "ARMv8.8-A";
|
||||
} else if (has_afp) {
|
||||
cpu->march = "ARMv8.7-A";
|
||||
} else if (has_i8mm && has_bf16) {
|
||||
cpu->march = "ARMv8.6-A";
|
||||
} else if (has_bti && has_sb && has_dcpodp && has_flagm2 && has_frint) {
|
||||
cpu->march = "ARMv8.5-A";
|
||||
} else if (has_dit && has_flagm && has_ilrcpc) {
|
||||
cpu->march = "ARMv8.4-A";
|
||||
} else if (has_paca && has_lrcpc && has_fcma && has_jscvt) {
|
||||
cpu->march = "ARMv8.3-A";
|
||||
} else if (has_fphp && has_dcpop) {
|
||||
cpu->march = "ARMv8.2-A";
|
||||
} else if (has_atomics && has_crc32 && has_asimdrdm) {
|
||||
cpu->march = "ARMv8.1-A";
|
||||
} else if (has_asimd && has_fp) {
|
||||
cpu->march = "ARMv8-A";
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif __APPLE__
|
||||
#include <sys/sysctl.h>
|
||||
#include <arm/cpu_capabilities_public.h>
|
||||
|
||||
#ifndef CAP_BIT_AdvSIMD
|
||||
#define CAP_BIT_AdvSIMD 49
|
||||
#endif
|
||||
#ifndef CAP_BIT_AdvSIMD_HPFPCvt
|
||||
#define CAP_BIT_AdvSIMD_HPFPCvt 50
|
||||
#endif
|
||||
#ifndef CAP_BIT_FEAT_CRC32
|
||||
#define CAP_BIT_FEAT_CRC32 51
|
||||
#endif
|
||||
#ifndef CAP_BIT_FEAT_HBC
|
||||
#define CAP_BIT_FEAT_HBC 64
|
||||
#endif
|
||||
#ifndef CAP_BIT_FEAT_CSSC
|
||||
#define CAP_BIT_FEAT_CSSC 67
|
||||
#endif
|
||||
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
uint64_t caps[2] = {0}; // 80-bit capability mask, split into two 64-bit values
|
||||
size_t size = sizeof(caps);
|
||||
|
||||
if (sysctlbyname("hw.optional.arm.caps", caps, &size, NULL, 0) != 0) return;
|
||||
|
||||
// Helper macro to test bit in 80-bit capability mask
|
||||
#define FF_HAS_CAP(bit) \
|
||||
(((bit) < 64) ? ((caps[0] >> (bit)) & 1ULL) : ((caps[1] >> ((bit) - 64U)) & 1ULL))
|
||||
|
||||
cpu->march = "unknown";
|
||||
|
||||
// ARMv8-A
|
||||
bool has_fp = FF_HAS_CAP(CAP_BIT_AdvSIMD_HPFPCvt); // Full FP16 support (implies FP/ASIMD)
|
||||
bool has_asimd = FF_HAS_CAP(CAP_BIT_AdvSIMD); // Advanced SIMD (NEON)
|
||||
|
||||
// ARMv8.1-A
|
||||
bool has_lse = FF_HAS_CAP(CAP_BIT_FEAT_LSE); // Large System Extensions, optional in v8.0
|
||||
bool has_crc32 = FF_HAS_CAP(CAP_BIT_FEAT_CRC32); // CRC32 instructions, optional in v8.0
|
||||
bool has_rdm = FF_HAS_CAP(CAP_BIT_FEAT_RDM); // AdvSIMD rounding double multiply accumulate, optional in v8.0
|
||||
|
||||
// ARMv8.2-A
|
||||
bool has_fp16 = FF_HAS_CAP(CAP_BIT_FEAT_FP16); // Half-precision FP support, optional
|
||||
bool has_dpb = FF_HAS_CAP(CAP_BIT_FEAT_DPB); // DC CVAP, optional from v8.1
|
||||
|
||||
// ARMv8.3-A
|
||||
bool has_pauth = FF_HAS_CAP(CAP_BIT_FEAT_PAuth); // Pointer Authentication (PAC), optional from v8.2
|
||||
bool has_lrcpc = FF_HAS_CAP(CAP_BIT_FEAT_LRCPC); // LDAPR/LR with RCPC semantics, optional from v8.2
|
||||
bool has_fcma = FF_HAS_CAP(CAP_BIT_FEAT_FCMA); // Complex number multiply-add, optional from v8.2
|
||||
bool has_jscvt = FF_HAS_CAP(CAP_BIT_FEAT_JSCVT); // JavaScript-style conversion (FJCVTZS), optional from v8.2
|
||||
|
||||
// ARMv8.4-A
|
||||
bool has_lse2 = FF_HAS_CAP(CAP_BIT_FEAT_LSE2); // Large System Extensions version 2, optional from v8.2
|
||||
bool has_dit = FF_HAS_CAP(CAP_BIT_FEAT_DIT); // Data Independent Timing, optional from v8.3
|
||||
bool has_flagm = FF_HAS_CAP(CAP_BIT_FEAT_FlagM); // Flag manipulation (FMOV/FCVT), optional from v8.1
|
||||
bool has_lrcpc2 = FF_HAS_CAP(CAP_BIT_FEAT_LRCPC2); // Enhanced RCPC (LDAPUR/LDAPST), optional from v8.2
|
||||
|
||||
// ARMv8.5-A
|
||||
bool has_bti = FF_HAS_CAP(CAP_BIT_FEAT_BTI); // Branch Target Identification, optional from v8.4
|
||||
bool has_sb = FF_HAS_CAP(CAP_BIT_FEAT_SB); // Speculative Barrier, optional from v8.0
|
||||
bool has_dpb2 = FF_HAS_CAP(CAP_BIT_FEAT_DPB2); // DC CVADP (DPB2), optional from v8.1
|
||||
bool has_flagm2 = FF_HAS_CAP(CAP_BIT_FEAT_FlagM2); // Enhanced FlagM, optional from v8.4
|
||||
bool has_frintts = FF_HAS_CAP(CAP_BIT_FEAT_FRINTTS); // Floating-point to integer instructions, optional from v8.4
|
||||
|
||||
// ARMv9.0-A
|
||||
bool has_sve2 = false; // Not exposed and not supported by Apple M4
|
||||
|
||||
// ARMv9.1-A
|
||||
// ARMv8.6-A
|
||||
bool has_bf16 = FF_HAS_CAP(CAP_BIT_FEAT_BF16); // Brain float16, optional from v8.2
|
||||
bool has_i8mm = FF_HAS_CAP(CAP_BIT_FEAT_I8MM); // Int8 Matrix Multiply, optional from v8.1
|
||||
|
||||
// ARMv8.7-A
|
||||
bool has_afp = FF_HAS_CAP(CAP_BIT_FEAT_AFP); // Alternate FP16 (FEXPA), optional from v8.6
|
||||
|
||||
// ARMv9.2-A
|
||||
bool has_sme = FF_HAS_CAP(CAP_BIT_FEAT_SME); // Scalable Matrix Extension, optional from v9.2
|
||||
|
||||
// ARMv9.3-A
|
||||
bool has_sme2 = FF_HAS_CAP(CAP_BIT_FEAT_SME2); // SME2, optional from v9.2
|
||||
|
||||
// ARMv8.8-A
|
||||
bool has_hbc = FF_HAS_CAP(CAP_BIT_FEAT_HBC); // Hinted conditional branches, optional from v8.7
|
||||
|
||||
// ARMv8.9-A
|
||||
bool has_cssc = FF_HAS_CAP(CAP_BIT_FEAT_CSSC); // Common Short String Compare, optional from v8.7
|
||||
|
||||
// ARMv9.4-A+ are not exposed yet
|
||||
|
||||
if (has_sve2 || has_sme) {
|
||||
// ARMv9 family
|
||||
if (has_sme2) {
|
||||
cpu->march = "ARMv9.3-A";
|
||||
} else if (has_sme) {
|
||||
cpu->march = "ARMv9.2-A";
|
||||
} else if (has_i8mm && has_bf16) {
|
||||
cpu->march = "ARMv9.1-A";
|
||||
} else {
|
||||
cpu->march = "ARMv9.0-A";
|
||||
}
|
||||
} else {
|
||||
// ARMv8 family
|
||||
if (has_cssc) {
|
||||
cpu->march = "ARMv8.9-A";
|
||||
} else if (has_hbc) {
|
||||
cpu->march = "ARMv8.8-A";
|
||||
} else if (has_afp) {
|
||||
cpu->march = "ARMv8.7-A";
|
||||
} else if (has_i8mm && has_bf16) {
|
||||
cpu->march = "ARMv8.6-A";
|
||||
} else if (has_bti && has_sb && has_dpb2 && has_flagm2 && has_frintts) {
|
||||
cpu->march = "ARMv8.5-A";
|
||||
} else if (has_lse2 && has_dit && has_flagm && has_lrcpc2) {
|
||||
cpu->march = "ARMv8.4-A";
|
||||
} else if (has_pauth && has_lrcpc && has_fcma && has_jscvt) {
|
||||
cpu->march = "ARMv8.3-A";
|
||||
} else if (has_fp16 && has_dpb) {
|
||||
cpu->march = "ARMv8.2-A";
|
||||
} else if (has_lse && has_crc32 && has_rdm) {
|
||||
cpu->march = "ARMv8.1-A";
|
||||
} else if (has_asimd && has_fp) {
|
||||
cpu->march = "ARMv8-A";
|
||||
}
|
||||
}
|
||||
|
||||
#undef HAS_CAP
|
||||
}
|
||||
#elif _WIN32
|
||||
#include <processthreadsapi.h>
|
||||
|
||||
// Missing from winnt.h of MinGW-w64
|
||||
#define PF_ARM_LSE2_AVAILABLE 62
|
||||
#define PF_RESERVED_FEATURE 63
|
||||
#define PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE 64
|
||||
#define PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE 65
|
||||
#define PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE 66
|
||||
#define PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE 67
|
||||
#define PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE 68
|
||||
#define PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE 69
|
||||
#define PF_ARM_SME_INSTRUCTIONS_AVAILABLE 70
|
||||
#define PF_ARM_SME2_INSTRUCTIONS_AVAILABLE 71
|
||||
#define PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE 72
|
||||
#define PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE 73
|
||||
#define PF_ARM_SME_AES_INSTRUCTIONS_AVAILABLE 74
|
||||
#define PF_ARM_SME_SBITPERM_INSTRUCTIONS_AVAILABLE 75
|
||||
#define PF_ARM_SME_SF8MM4_INSTRUCTIONS_AVAILABLE 76
|
||||
#define PF_ARM_SME_SF8MM8_INSTRUCTIONS_AVAILABLE 77
|
||||
#define PF_ARM_SME_SF8DP2_INSTRUCTIONS_AVAILABLE 78
|
||||
#define PF_ARM_SME_SF8DP4_INSTRUCTIONS_AVAILABLE 79
|
||||
#define PF_ARM_SME_SF8FMA_INSTRUCTIONS_AVAILABLE 80
|
||||
#define PF_ARM_SME_F8F32_INSTRUCTIONS_AVAILABLE 81
|
||||
#define PF_ARM_SME_F8F16_INSTRUCTIONS_AVAILABLE 82
|
||||
#define PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE 83
|
||||
#define PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE 84
|
||||
#define PF_ARM_SME_F64F64_INSTRUCTIONS_AVAILABLE 85
|
||||
#define PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE 86
|
||||
#define PF_ARM_SME_LUTv2_INSTRUCTIONS_AVAILABLE 87
|
||||
#define PF_ARM_SME_FA64_INSTRUCTIONS_AVAILABLE 88
|
||||
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
// ARMv8-A
|
||||
bool has_vfp = IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE); // Implies basic FP support
|
||||
bool has_neon = IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE); // NEON (ASIMD)
|
||||
|
||||
// ARMv8.1-A
|
||||
bool has_atomics = IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE); // LSE atomics
|
||||
bool has_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); // CRC32
|
||||
|
||||
// ARMv8.2-A
|
||||
bool has_fp16 = IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE); // Half-precision FP
|
||||
|
||||
// ARMv8.3-A
|
||||
bool has_lrcpc = IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE); // LDAPR/LR with RCPC semantics
|
||||
bool has_jscvt = IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE); // FJCVTZS
|
||||
|
||||
// ARMv8.4-A
|
||||
// My CPU (Apple M1 Pro in VM) does support LSE2, but Windows doesn't detect it for some reason
|
||||
// bool has_lse2 = IsProcessorFeaturePresent(PF_ARM_LSE2_AVAILABLE); // Large System Extensions version 2, optional from v8.2
|
||||
bool has_dp = IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE); // DotProd, optional from v8.1 (*)
|
||||
|
||||
// ARMv9.0-A
|
||||
bool has_sve2 = IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE); // SVE2
|
||||
|
||||
// ARMv9.1-A
|
||||
// ARMv8.6-A
|
||||
bool has_bf16 = IsProcessorFeaturePresent(PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE); // BF16, optional from v8.2
|
||||
bool has_i8mm = IsProcessorFeaturePresent(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE); // Int8 matrix multiply, optional from v8.2
|
||||
|
||||
// ARMv8.7-A
|
||||
bool has_ebf16 = IsProcessorFeaturePresent(PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE); // Extended BFloat16 behaviors, optional from v8.2
|
||||
|
||||
// ARMv9.2-A
|
||||
bool has_sme = IsProcessorFeaturePresent(PF_ARM_SME_INSTRUCTIONS_AVAILABLE); // SME
|
||||
|
||||
// ARMv9.3-A
|
||||
bool has_sme2 = IsProcessorFeaturePresent(PF_ARM_SME2_INSTRUCTIONS_AVAILABLE); // SME2
|
||||
|
||||
// ARMv9.4-A
|
||||
bool has_sme2p1 = IsProcessorFeaturePresent(PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE); // SME2.1
|
||||
|
||||
|
||||
if (has_sve2 || has_sme)
|
||||
{
|
||||
// ARMv9 family
|
||||
if (has_sme2p1) {
|
||||
cpu->march = "ARMv9.4-A";
|
||||
} else if (has_sme2) {
|
||||
cpu->march = "ARMv9.3-A";
|
||||
} else if (has_sme) {
|
||||
cpu->march = "ARMv9.2-A";
|
||||
} else if (has_i8mm && has_bf16) {
|
||||
cpu->march = "ARMv9.1-A";
|
||||
} else {
|
||||
cpu->march = "ARMv9.0-A";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ARMv8 family
|
||||
if (has_ebf16) {
|
||||
cpu->march = "ARMv8.7-A";
|
||||
} else if (has_i8mm && has_bf16) {
|
||||
cpu->march = "ARMv8.6-A";
|
||||
} else if (has_dp) {
|
||||
cpu->march = "ARMv8.4-A";
|
||||
} else if (has_lrcpc && has_jscvt) {
|
||||
cpu->march = "ARMv8.3-A";
|
||||
} else if (has_fp16) {
|
||||
cpu->march = "ARMv8.2-A";
|
||||
} else if (has_atomics && has_crc32) {
|
||||
cpu->march = "ARMv8.1-A";
|
||||
} else if (has_neon && has_vfp) {
|
||||
cpu->march = "ARMv8-A";
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void ffCPUDetectByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu)
|
||||
{
|
||||
// Unsupported system
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
void ffCPUDetectByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu)
|
||||
{
|
||||
// Unsupported architecture
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+4
-27
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cpu/option.h"
|
||||
|
||||
#define FF_CPU_TEMP_UNSET (0/0.0)
|
||||
#define FF_CPU_TEMP_UNSET (-DBL_MAX)
|
||||
|
||||
typedef struct FFCPUCore
|
||||
{
|
||||
@@ -14,6 +15,7 @@ typedef struct FFCPUResult
|
||||
{
|
||||
FFstrbuf name;
|
||||
FFstrbuf vendor;
|
||||
const char* march; // Microarchitecture
|
||||
|
||||
uint16_t packages;
|
||||
uint16_t coresPhysical;
|
||||
@@ -31,29 +33,4 @@ typedef struct FFCPUResult
|
||||
const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu);
|
||||
const char* ffCPUAppleCodeToName(uint32_t code);
|
||||
const char* ffCPUQualcommCodeToName(uint32_t code);
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
|
||||
#include <cpuid.h>
|
||||
|
||||
// WARNING: CPUID may report frequencies of efficient cores
|
||||
inline static const char* ffCPUDetectSpeedByCpuid(FFCPUResult* cpu)
|
||||
{
|
||||
uint32_t base = 0, max = 0, bus = 0, unused = 0;
|
||||
if (!__get_cpuid(0x16, &base, &max, &bus, &unused))
|
||||
return "Unsupported instruction";
|
||||
|
||||
// cpuid returns 0 MHz when hyper-v is enabled
|
||||
if (base) cpu->frequencyBase = base;
|
||||
if (max) cpu->frequencyMax = max;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline static const char* ffCPUDetectSpeedByCpuid(FF_MAYBE_UNUSED FFCPUResult* cpu)
|
||||
{
|
||||
return "Unsupported platform";
|
||||
}
|
||||
|
||||
#endif
|
||||
void ffCPUDetectByCpuid(FFCPUResult* cpu);
|
||||
|
||||
@@ -126,6 +126,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
if(cpu->coresOnline == 1)
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.activecpu", 1);
|
||||
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
detectFrequency(cpu);
|
||||
if (options->showPeCoreCount) detectCoreCount(cpu);
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(cpuset_t), ¤tCPU);
|
||||
#endif
|
||||
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
|
||||
uint32_t clockrate = (uint32_t) ffSysctlGetInt("hw.clockrate", 0);
|
||||
if (clockrate > cpu->frequencyBase) cpu->frequencyBase = clockrate;
|
||||
|
||||
@@ -55,7 +55,7 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe
|
||||
ffStrbufSetF(&cpu->name, "(Unknown %" B_PRIx32 ")", cpuModel);
|
||||
ffStrbufSetS(&cpu->vendor, get_cpu_vendor_string(cpuVendor));
|
||||
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
if (cpu->frequencyBase < frequency) cpu->frequencyBase = frequency;
|
||||
cpu->packages = packages;
|
||||
cpu->coresPhysical = cores;
|
||||
|
||||
+165
-128
@@ -13,84 +13,129 @@
|
||||
|
||||
#define FF_CPUINFO_PATH "/proc/cpuinfo"
|
||||
|
||||
static double parseHwmonDir(FFstrbuf* dir, FFstrbuf* buffer)
|
||||
static double parseTZDir(int dfd, FFstrbuf* buffer)
|
||||
{
|
||||
//https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
|
||||
uint32_t dirLength = dir->length;
|
||||
ffStrbufAppendS(dir, "temp1_input");
|
||||
if (!ffReadFileBufferRelative(dfd, "type", buffer))
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
if(!ffReadFileBuffer(dir->chars, buffer))
|
||||
{
|
||||
// Some badly implemented system put temp file in /hwmonN/device
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
ffStrbufAppendS(dir, "device/");
|
||||
dirLength = dir->length;
|
||||
ffStrbufAppendS(dir, "temp1_input");
|
||||
if (!ffStrbufStartsWithS(buffer, "cpu") &&
|
||||
!ffStrbufStartsWithS(buffer, "soc") &&
|
||||
#if __x86_64__ || __i386__
|
||||
!ffStrbufEqualS(buffer, "x86_pkg_temp") &&
|
||||
#endif
|
||||
true
|
||||
) return FF_CPU_TEMP_UNSET;
|
||||
|
||||
if(!ffReadFileBuffer(dir->chars, buffer))
|
||||
return 0.0/0.0;
|
||||
}
|
||||
if (!ffReadFileBufferRelative(dfd, "temp", buffer))
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
double value = ffStrbufToDouble(buffer, FF_CPU_TEMP_UNSET);// millidegree Celsius
|
||||
if (value == FF_CPU_TEMP_UNSET)
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
double value = ffStrbufToDouble(buffer);// millidegree Celsius
|
||||
return value / 1000.;
|
||||
}
|
||||
|
||||
if(value != value)
|
||||
return 0.0/0.0;
|
||||
|
||||
ffStrbufAppendS(dir, "name");
|
||||
if (!ffReadFileBuffer(dir->chars, buffer))
|
||||
return 0.0/0.0;
|
||||
static double parseHwmonDir(int dfd, FFstrbuf* buffer)
|
||||
{
|
||||
if (!ffReadFileBufferRelative(dfd, "name", buffer))
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
|
||||
if(
|
||||
ffStrbufContainS(buffer, "cpu") ||
|
||||
ffStrbufEqualS(buffer, "k10temp") || // AMD
|
||||
ffStrbufEqualS(buffer, "fam15h_power") || // AMD
|
||||
ffStrbufEqualS(buffer, "coretemp") // Intel
|
||||
) return value / 1000.;
|
||||
if (
|
||||
!ffStrbufContainS(buffer, "cpu") &&
|
||||
#if __x86_64__ || __i386__
|
||||
!ffStrbufEqualS(buffer, "k10temp") && // AMD
|
||||
!ffStrbufEqualS(buffer, "fam15h_power") && // AMD
|
||||
!ffStrbufEqualS(buffer, "coretemp") && // Intel
|
||||
#endif
|
||||
true
|
||||
) return FF_CPU_TEMP_UNSET;
|
||||
|
||||
return 0.0/0.0;
|
||||
}
|
||||
//https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
|
||||
if (!ffReadFileBufferRelative(dfd, "temp1_input", buffer))
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
static double detectTZTemp(FFstrbuf* buffer)
|
||||
{
|
||||
if (ffReadFileBuffer("/sys/class/thermal/thermal_zone0/temp", buffer))
|
||||
return ffStrbufToDouble(buffer) / 1000.;
|
||||
return 0.0/0.0;
|
||||
double value = ffStrbufToDouble(buffer, FF_CPU_TEMP_UNSET);// millidegree Celsius
|
||||
if (value == FF_CPU_TEMP_UNSET)
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
|
||||
return value / 1000.;
|
||||
}
|
||||
|
||||
static double detectCPUTemp(void)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);
|
||||
ffStrbufAppendS(&baseDir, "/sys/class/hwmon/");
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
uint32_t baseDirLength = baseDir.length;
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars);
|
||||
if(dirp == NULL)
|
||||
return 0.0/0.0;
|
||||
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
continue;
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/hwmon/");
|
||||
if(dirp)
|
||||
{
|
||||
int dfd = dirfd(dirp);
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
ffStrbufAppendS(&baseDir, entry->d_name);
|
||||
ffStrbufAppendC(&baseDir, '/');
|
||||
FF_AUTO_CLOSE_FD int subfd = openat(dfd, entry->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if(subfd < 0)
|
||||
continue;
|
||||
|
||||
double result = parseHwmonDir(&baseDir, &buffer);
|
||||
if (result == result)
|
||||
return result;
|
||||
double result = parseHwmonDir(subfd, &buffer);
|
||||
if (result != FF_CPU_TEMP_UNSET)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/thermal/");
|
||||
if(dirp)
|
||||
{
|
||||
int dfd = dirfd(dirp);
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
continue;
|
||||
if(!ffStrStartsWith(entry->d_name, "thermal_zone"))
|
||||
continue;
|
||||
|
||||
ffStrbufSubstrBefore(&baseDir, baseDirLength);
|
||||
FF_AUTO_CLOSE_FD int subfd = openat(dfd, entry->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if(subfd < 0)
|
||||
continue;
|
||||
|
||||
double result = parseTZDir(subfd, &buffer);
|
||||
if (result != FF_CPU_TEMP_UNSET)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/devices/platform/");
|
||||
if(dirp)
|
||||
{
|
||||
int dfd = dirfd(dirp);
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(entry->d_name[0] == '.')
|
||||
continue;
|
||||
if(!ffStrStartsWith(entry->d_name, "cputemp."))
|
||||
continue;
|
||||
|
||||
FF_AUTO_CLOSE_FD int subfd = openat(dfd, entry->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if(subfd < 0)
|
||||
continue;
|
||||
|
||||
double result = parseHwmonDir(subfd, &buffer);
|
||||
if (result != FF_CPU_TEMP_UNSET)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return detectTZTemp(&buffer);
|
||||
return FF_CPU_TEMP_UNSET;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
@@ -100,85 +145,75 @@ static void detectQualcomm(FFCPUResult* cpu)
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/List_of_Qualcomm_Snapdragon_systems_on_chips
|
||||
|
||||
if (ffStrbufEqualS(&cpu->name, "SM8750-AC"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite for Galaxy [SM8750-AC]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8750-3"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite [SM8750-3]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8750"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Elite [SM8750]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8635"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8s Gen 3 [SM8635]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8650-AC"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 3 for Galaxy [SM8650-AC]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8650"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 3 [SM8650]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8550-AC"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 2 for Galaxy [SM8550-AC]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8550"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 2 [SM8550]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8475"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8+ Gen 1 [SM8475]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM8450"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 8 Gen 1 [SM8450]");
|
||||
uint32_t code = (uint32_t) strtoul(cpu->name.chars + 2, NULL, 10);
|
||||
const char* name = NULL;
|
||||
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7675"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7+ Gen 3 [SM7675]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7635"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7s Gen 3 [SM7635]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7550"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7 Gen 3 [SM7550]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7475"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7+ Gen 2 [SM7550]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7435"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7s Gen 2 [SM7435]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM7450"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 7 Gen 1 [SM7450]");
|
||||
switch (code)
|
||||
{
|
||||
case 8735: name = "8s Gen 4"; break;
|
||||
case 8750: name = "8 Elite"; break;
|
||||
case 8635: name = "8s Gen 3"; break;
|
||||
case 8650: name = "8 Gen 3"; break;
|
||||
case 8550: name = "8 Gen 2"; break;
|
||||
case 8475: name = "8+ Gen 1"; break;
|
||||
case 8450: name = "8 Gen 1"; break;
|
||||
case 7750: name = "7 Gen 4"; break;
|
||||
case 7675: name = "7+ Gen 3"; break;
|
||||
case 7635: name = "7s Gen 3"; break;
|
||||
case 7550: name = "7 Gen 3"; break;
|
||||
case 7475: name = "7+ Gen 2"; break;
|
||||
case 7435: name = "7s Gen 2"; break;
|
||||
case 7450: name = "7 Gen 1"; break;
|
||||
case 6650: name = "6 Gen 4"; break;
|
||||
case 6375: name = "6s Gen 3"; break;
|
||||
case 6475: name = "6 Gen 3"; break;
|
||||
case 6115: name = "6s Gen 1"; break;
|
||||
case 6450: name = "6 Gen 1"; break;
|
||||
case 4635: name = "4s Gen 2"; break;
|
||||
case 4450: name = "4 Gen 2"; break;
|
||||
case 4375: name = "4 Gen 1"; break;
|
||||
}
|
||||
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM6375-AC"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6s Gen 3 [SM6375-AC]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM6475"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6 Gen 3 [SM6475]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM6115"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6s Gen 1 [SM6115]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM6450"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 6 Gen 1 [SM6450]");
|
||||
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM4635"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4s Gen 2 [SM4635]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM4450"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4 Gen 2 [SM4450]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "SM4375"))
|
||||
ffStrbufSetStatic(&cpu->name, "Qualcomm Snapdragon 4 Gen 1 [SM4375]");
|
||||
if (name)
|
||||
{
|
||||
char str[32];
|
||||
ffStrCopy(str, cpu->name.chars, sizeof(str));
|
||||
ffStrbufSetF(&cpu->name, "Qualcomm Snapdragon %s [%s]", name, str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void detectMediaTek(FFCPUResult* cpu)
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/List_of_MediaTek_systems_on_chips
|
||||
|
||||
if (ffStrbufEqualS(&cpu->name, "MT6991"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9400 [MT6991]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6991Z"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9400 [MT6991Z]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6989Z"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300+ [MT6989Z]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT8796Z"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300+ [MT8796Z]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6989"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300 [MT6989]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT8796"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9300 [MT8796]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6985W"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9200+ [MT6985W]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6985"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9200 [MT6985]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6983W"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000+ [MT6983W]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT8798Z/T"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000+ [MT8798Z/T]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT6983Z"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000 [MT6983Z]");
|
||||
else if (ffStrbufEqualS(&cpu->name, "MT8798Z/C"))
|
||||
ffStrbufSetStatic(&cpu->name, "MediaTek Dimensity 9000 [MT8798Z/C]");
|
||||
uint32_t code = (uint32_t) strtoul(cpu->name.chars + 2, NULL, 10);
|
||||
const char* name = NULL;
|
||||
|
||||
switch (code) // The SOC code of MTK Dimensity series is full of mess
|
||||
{
|
||||
case 6991: name = "9400"; break;
|
||||
case 6989:
|
||||
case 8796: name = "9300"; break;
|
||||
case 6985: name = "9200"; break;
|
||||
case 6983:
|
||||
case 8798: name = "9000"; break;
|
||||
|
||||
case 6899: name = "8400"; break;
|
||||
case 6897:
|
||||
case 8792: name = "8300"; break;
|
||||
case 6896: name = "8200"; break;
|
||||
case 8795: name = "8100"; break;
|
||||
case 6895: name = "8000"; break;
|
||||
}
|
||||
|
||||
if (name)
|
||||
{
|
||||
char str[32];
|
||||
ffStrCopy(str, cpu->name.chars, sizeof(str));
|
||||
ffStrbufSetF(&cpu->name, "MediaTek Dimensity %s [%s]", name, str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void detectAndroid(FFCPUResult* cpu)
|
||||
@@ -463,7 +498,7 @@ FF_MAYBE_UNUSED static const char* detectCPUX86(const FFCPUOptions* options, FFC
|
||||
cpu->coresPhysical *= cpu->packages;
|
||||
|
||||
// Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
if (!detectFrequency(cpu, options) || cpu->frequencyBase == 0)
|
||||
cpu->frequencyBase = (uint32_t) ffStrbufToUInt(&cpuMHz, 0);
|
||||
|
||||
@@ -741,6 +776,8 @@ FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options,
|
||||
if (cpu->coresPhysical == 0)
|
||||
detectPhysicalCores(cpu);
|
||||
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -64,7 +64,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
cpu->coresLogical = cpu->coresPhysical;
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt("hw.ncpuonline", cpu->coresLogical);
|
||||
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
|
||||
uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
|
||||
if (freq == 0) freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
|
||||
|
||||
@@ -56,7 +56,7 @@ const char *ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
cpu->coresLogical = cpu->coresPhysical;
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt(CTL_HW, HW_NCPUONLINE, cpu->coresLogical);
|
||||
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
|
||||
uint32_t cpuspeed = (uint32_t) ffSysctlGetInt(CTL_HW, HW_CPUSPEED, 0);
|
||||
if (cpuspeed > cpu->frequencyBase) cpu->frequencyBase = cpuspeed;
|
||||
|
||||
@@ -122,7 +122,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "vendor_id");
|
||||
if (kn) ffStrbufSetNS(&cpu->vendor, KSTAT_NAMED_STR_BUFLEN(kn) - 1, KSTAT_NAMED_STR_PTR(kn));
|
||||
}
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "clock_MHz");
|
||||
if (kn && kn->value.ui32 > cpu->frequencyBase)
|
||||
|
||||
@@ -287,7 +287,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ffCPUDetectSpeedByCpuid(cpu);
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
if (options->showPeCoreCount) detectCoreTypes(cpu);
|
||||
|
||||
if (cpu->frequencyMax == 0)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cpucache/option.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFCPUCacheType
|
||||
{
|
||||
|
||||
@@ -54,6 +54,7 @@ retry:
|
||||
ffTimeSleep(options->waitTime);
|
||||
goto retry;
|
||||
}
|
||||
return "CPU time did not increase. Try increasing wait time.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cpuusage/option.h"
|
||||
|
||||
typedef struct FFCpuUsageInfo {
|
||||
uint64_t inUseAll;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/cursor/option.h"
|
||||
|
||||
typedef struct FFCursorResult
|
||||
{
|
||||
|
||||
@@ -2,19 +2,30 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
static void appendColor(FFstrbuf* str, NSDictionary* color)
|
||||
static void appendColor(FFstrbuf* str, NSDictionary* dict)
|
||||
{
|
||||
int r = (int) (((NSNumber*) color[@"red"]).doubleValue * 255);
|
||||
int g = (int) (((NSNumber*) color[@"green"]).doubleValue * 255);
|
||||
int b = (int) (((NSNumber*) color[@"blue"]).doubleValue * 255);
|
||||
int a = (int) (((NSNumber*) color[@"alpha"]).doubleValue * 255);
|
||||
uint32_t r = (uint32_t) (((NSNumber*) dict[@"red"]).doubleValue * 255 + .5);
|
||||
uint32_t g = (uint32_t) (((NSNumber*) dict[@"green"]).doubleValue * 255 + .5);
|
||||
uint32_t b = (uint32_t) (((NSNumber*) dict[@"blue"]).doubleValue * 255 + .5);
|
||||
uint32_t a = (uint32_t) (((NSNumber*) dict[@"alpha"]).doubleValue * 255 + .5);
|
||||
uint32_t color = (r << 24) | (g << 16) | (b << 8) | a;
|
||||
|
||||
if (r == 255 && g == 255 && b == 255 && a == 255)
|
||||
ffStrbufAppendS(str, "White");
|
||||
else if (r == 0 && g == 0 && b == 0 && a == 255)
|
||||
ffStrbufAppendS(str, "Black");
|
||||
else
|
||||
ffStrbufAppendF(str, "#%02X%02X%02X%02X", r, g, b, a);
|
||||
switch (color)
|
||||
{
|
||||
case 0x000000FF: ffStrbufAppendS(str, "Black"); return;
|
||||
case 0x0433FFFF: ffStrbufAppendS(str, "Blue"); return;
|
||||
case 0xAA7942FF: ffStrbufAppendS(str, "Brown"); return;
|
||||
case 0x00FDFFFF: ffStrbufAppendS(str, "Cyan"); return;
|
||||
case 0x00F900FF: ffStrbufAppendS(str, "Green"); return;
|
||||
case 0xFF40FFFF: ffStrbufAppendS(str, "Magenta"); return;
|
||||
case 0xFF9300FF: ffStrbufAppendS(str, "Orange"); return;
|
||||
case 0x942192FF: ffStrbufAppendS(str, "Purple"); return;
|
||||
case 0xFF2600FF: ffStrbufAppendS(str, "Red"); return;
|
||||
case 0xFFFB00FF: ffStrbufAppendS(str, "Yellow"); return;
|
||||
case 0xFFFFFFFF: ffStrbufAppendS(str, "White"); return;
|
||||
case 0x00000000: ffStrbufAppendS(str, "Transparent"); return;
|
||||
default: ffStrbufAppendF(str, "#%08X", color); return;
|
||||
}
|
||||
}
|
||||
|
||||
void ffDetectCursor(FFCursorResult* result)
|
||||
@@ -46,7 +57,7 @@ void ffDetectCursor(FFCursorResult* result)
|
||||
|
||||
NSNumber* mouseDriverCursorSize = dict[@"mouseDriverCursorSize"];
|
||||
if (mouseDriverCursorSize)
|
||||
ffStrbufAppendF(&result->size, "%d", (int) (mouseDriverCursorSize.doubleValue * 32));
|
||||
ffStrbufAppendF(&result->size, "%d", (int) (mouseDriverCursorSize.doubleValue * 32 + 0.5));
|
||||
else
|
||||
ffStrbufAppendS(&result->size, "32");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/de/option.h"
|
||||
|
||||
const char* ffDetectDEVersion(const FFstrbuf* deName, FFstrbuf* result, FFDEOptions* options);
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
#include "common/parsing.h"
|
||||
#include "common/properties.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/binary.h"
|
||||
#include "util/path.h"
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#ifdef __FreeBSD__
|
||||
@@ -195,6 +196,45 @@ static void getUnity(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options)
|
||||
ffStrbufSubstrBeforeFirstC(result, '"');
|
||||
}
|
||||
|
||||
static bool extractTdeVersion(const char* line, uint32_t len, void *userdata)
|
||||
{
|
||||
int count = 0;
|
||||
sscanf(line, "R%*d.%*d.%*d%n", &count);
|
||||
if (count == 0) return true;
|
||||
|
||||
ffStrbufSetNS((FFstrbuf*) userdata, len, line);
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* getTrinity(FFstrbuf* result, FFDEOptions* options)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
const char* error = ffFindExecutableInPath("tde-config", &path);
|
||||
if (error) return "Failed to find tde-config path";
|
||||
|
||||
ffStrbufSubstrBeforeLastC(&path, '/');
|
||||
ffStrbufAppendS(&path, "/../lib/libtdecore.so");
|
||||
|
||||
if (ffBinaryExtractStrings(path.chars, extractTdeVersion, result, strlen("R0.0.0")) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (options->slowVersionDetection)
|
||||
{
|
||||
ffStrbufClear(&path);
|
||||
ffProcessAppendStdOut(&path, (char* const[]){
|
||||
"tde-config",
|
||||
"--version",
|
||||
NULL
|
||||
});
|
||||
|
||||
ffParsePropLines(path.chars , "TDE: ", result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "All methods failed";
|
||||
}
|
||||
|
||||
|
||||
const char* ffDetectDEVersion(const FFstrbuf* deName, FFstrbuf* result, FFDEOptions* options)
|
||||
{
|
||||
if (!instance.config.general.detectVersion) return "Disabled by config";
|
||||
@@ -215,6 +255,8 @@ const char* ffDetectDEVersion(const FFstrbuf* deName, FFstrbuf* result, FFDEOpti
|
||||
getBudgie(result, options);
|
||||
else if (ffStrbufEqualS(deName, FF_DE_PRETTY_UNITY))
|
||||
getUnity(result, options);
|
||||
else if (ffStrbufEqualS(deName, "trinity"))
|
||||
getTrinity(result, options);
|
||||
else
|
||||
return "Unsupported DE";
|
||||
return NULL;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/disk/option.h"
|
||||
|
||||
typedef struct FFDisk
|
||||
{
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <mntent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#ifdef __USE_LARGEFILE64
|
||||
#define stat stat64
|
||||
@@ -55,6 +54,9 @@ static bool isPhysicalDevice(const struct mntent* device)
|
||||
ffStrStartsWith(device->mnt_fsname + 5, "fd") //Ignore fd devices
|
||||
) return false;
|
||||
|
||||
if (ffStrStartsWith(device->mnt_dir, "/bedrock/")) // Ignore Bedrock Linux subvolumes
|
||||
return false;
|
||||
|
||||
struct stat deviceStat;
|
||||
if(stat(device->mnt_fsname, &deviceStat) != 0)
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/diskio/option.h"
|
||||
|
||||
typedef struct FFDiskIOResult
|
||||
{
|
||||
|
||||
@@ -23,8 +23,8 @@ static const char* parseDiskIOCounters(int dfd, const char* devName, FFlist* res
|
||||
ffStrbufAppendC(&name, ' ');
|
||||
}
|
||||
|
||||
if (ffAppendFileBufferRelative(devfd, "model", &name))
|
||||
ffStrbufTrimRightSpace(&name);
|
||||
ffAppendFileBufferRelative(devfd, "model", &name);
|
||||
ffStrbufTrimRightSpace(&name);
|
||||
|
||||
if (name.length == 0)
|
||||
ffStrbufSetS(&name, devName);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/display/option.h"
|
||||
|
||||
#define FF_DE_PRETTY_PLASMA "KDE Plasma"
|
||||
#define FF_DE_PRETTY_GNOME "GNOME"
|
||||
|
||||
@@ -147,8 +147,8 @@ static bool detectWithGetprop(FFDisplayServerResult* ds)
|
||||
|
||||
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
{
|
||||
ffStrbufSetStatic(&ds->wmProcessName, "WindowManager");
|
||||
ffStrbufSetStatic(&ds->wmPrettyName, "Window Manager");
|
||||
ffStrbufSetStatic(&ds->wmProcessName, "surfaceflinger");
|
||||
ffStrbufSetStatic(&ds->wmPrettyName, "SurfaceFlinger");
|
||||
|
||||
if (!detectWithGetprop(ds))
|
||||
detectWithDumpsys(ds);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Generated by wayland-scanner 1.23.1 */
|
||||
/* Generated by wayland-scanner 1.24.0 */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_CLIENT_PROTOCOL_H
|
||||
#define KDE_OUTPUT_DEVICE_V2_CLIENT_PROTOCOL_H
|
||||
@@ -234,6 +234,11 @@ enum kde_output_device_v2_capability {
|
||||
* @since 16
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR = 0x800,
|
||||
/**
|
||||
* if this outputdevice supports the sharpness setting
|
||||
* @since 17
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_SHARPNESS = 0x1000,
|
||||
};
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
@@ -271,6 +276,10 @@ enum kde_output_device_v2_capability {
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR_SINCE_VERSION 16
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_SHARPNESS_SINCE_VERSION 17
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM
|
||||
@@ -774,6 +783,17 @@ struct kde_output_device_v2_listener {
|
||||
void (*edr_policy)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t policy);
|
||||
/**
|
||||
* sharpness strength
|
||||
*
|
||||
* This is the sharpness modifier of the output. 0 is sharpness
|
||||
* disabled and 10000 is the maximum sharpness
|
||||
* @param sharpness sharpness in 0-10000
|
||||
* @since 17
|
||||
*/
|
||||
void (*sharpness)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t sharpness);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -919,6 +939,10 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_SINCE_VERSION 16
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_SHARPNESS_SINCE_VERSION 17
|
||||
|
||||
|
||||
/** @ingroup iface_kde_output_device_v2 */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
|
||||
/* Generated by wayland-scanner 1.23.1 */
|
||||
/* Generated by wayland-scanner 1.24.0 */
|
||||
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2008-2011 Kristian Høgsberg
|
||||
@@ -66,12 +66,13 @@ static const struct wl_message kde_output_device_v2_events[] = {
|
||||
{ "max_bits_per_color_range", "15uu", kde_output_device_v2_types + 0 },
|
||||
{ "automatic_max_bits_per_color_limit", "15u", kde_output_device_v2_types + 0 },
|
||||
{ "edr_policy", "16u", kde_output_device_v2_types + 0 },
|
||||
{ "sharpness", "17u", kde_output_device_v2_types + 0 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
|
||||
"kde_output_device_v2", 16,
|
||||
"kde_output_device_v2", 17,
|
||||
0, NULL,
|
||||
33, kde_output_device_v2_events,
|
||||
34, kde_output_device_v2_events,
|
||||
};
|
||||
|
||||
static const struct wl_message kde_output_device_mode_v2_events[] = {
|
||||
|
||||
@@ -177,6 +177,7 @@ static struct kde_output_device_v2_listener outputListener = {
|
||||
.max_bits_per_color_range = (void*) stubListener,
|
||||
.automatic_max_bits_per_color_limit = (void*) stubListener,
|
||||
.edr_policy = (void*) stubListener,
|
||||
.sharpness = (void*) stubListener,
|
||||
};
|
||||
|
||||
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
static bool waylandDetectWM(int fd, FFDisplayServerResult* result)
|
||||
{
|
||||
#if __linux__ || (__FreeBSD__ && !__DragonFly__)
|
||||
#if __linux__ || __GNU__ || (__FreeBSD__ && !__DragonFly__)
|
||||
|
||||
#if __linux
|
||||
#if __linux__ || __GNU__
|
||||
struct ucred ucred = {};
|
||||
socklen_t len = sizeof(ucred);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1 || ucred.pid <= 0)
|
||||
|
||||
@@ -351,7 +351,7 @@ static const char* getFromProcesses(FFDisplayServerResult* result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#elif __linux__
|
||||
#elif __linux__ || __GNU__
|
||||
FF_AUTO_CLOSE_DIR DIR* procdir = opendir("/proc");
|
||||
if(procdir == NULL)
|
||||
return "opendir(\"/proc\") failed";
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/time.h"
|
||||
#include "util/edidHelper.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -24,6 +25,9 @@ typedef struct XcbPropertyData
|
||||
FF_LIBRARY_SYMBOL(xcb_get_atom_name_name)
|
||||
FF_LIBRARY_SYMBOL(xcb_get_atom_name_name_length)
|
||||
FF_LIBRARY_SYMBOL(xcb_get_atom_name_reply)
|
||||
FF_LIBRARY_SYMBOL(xcb_get_setup)
|
||||
FF_LIBRARY_SYMBOL(xcb_setup_vendor)
|
||||
FF_LIBRARY_SYMBOL(xcb_setup_vendor_length)
|
||||
} XcbPropertyData;
|
||||
|
||||
static bool xcbInitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, XcbPropertyData* propertyData)
|
||||
@@ -38,6 +42,9 @@ static bool xcbInitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, XcbProperty
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_name, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_name_length, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_atom_name_reply, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_get_setup, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_setup_vendor, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, xcb_setup_vendor_length, false)
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -76,16 +83,33 @@ static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connect
|
||||
if(wmWindow == NULL)
|
||||
return;
|
||||
|
||||
FF_AUTO_FREE char* wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "_NET_WM_NAME");
|
||||
if(wmName == NULL)
|
||||
wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "WM_NAME");
|
||||
FF_AUTO_FREE char* wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "WM_NAME");
|
||||
if(!ffStrSet(wmName))
|
||||
wmName = (char*) xcbGetProperty(data, connection, *wmWindow, "_NET_WM_NAME");
|
||||
|
||||
if(wmName == NULL || *wmName == '\0')
|
||||
if(!ffStrSet(wmName))
|
||||
return;
|
||||
|
||||
ffStrbufSetS(&result->wmProcessName, wmName);
|
||||
}
|
||||
|
||||
static void xcbFetchServerVendor(XcbPropertyData* data, xcb_connection_t* connection, FFDisplayServerResult* result)
|
||||
{
|
||||
const xcb_setup_t* setup = data->ffxcb_get_setup(connection);
|
||||
|
||||
int length = data->ffxcb_setup_vendor_length(setup);
|
||||
if(length <= 0)
|
||||
return;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY serverVendor = ffStrbufCreateNS((uint32_t) length, data->ffxcb_setup_vendor(setup));
|
||||
|
||||
if (!ffStrbufEqualS(&serverVendor, "The X.Org Foundation")) // Original
|
||||
{
|
||||
ffStrbufDestroy(&result->wmProtocolName);
|
||||
ffStrbufInitMove(&result->wmProtocolName, &serverVendor);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct XcbRandrData
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources_current)
|
||||
@@ -381,8 +405,10 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(data.connection));
|
||||
|
||||
|
||||
if(iterator.rem > 0 && propertyDataInitialized)
|
||||
if(iterator.rem > 0 && propertyDataInitialized) {
|
||||
xcbDetectWMfromEWMH(&data.propData, data.connection, iterator.data->root, result);
|
||||
xcbFetchServerVendor(&data.propData, data.connection, result);
|
||||
}
|
||||
|
||||
|
||||
while(iterator.rem > 0)
|
||||
|
||||
@@ -14,6 +14,7 @@ typedef struct X11PropertyData
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(XInternAtom)
|
||||
FF_LIBRARY_SYMBOL(XGetWindowProperty)
|
||||
FF_LIBRARY_SYMBOL(XServerVendor)
|
||||
FF_LIBRARY_SYMBOL(XFree)
|
||||
} X11PropertyData;
|
||||
|
||||
@@ -21,6 +22,7 @@ static bool x11InitPropertyData(FF_MAYBE_UNUSED void* libraryHandle, X11Property
|
||||
{
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XInternAtom, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XGetWindowProperty, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XServerVendor, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(libraryHandle, propertyData, XFree, false)
|
||||
|
||||
return true;
|
||||
@@ -51,9 +53,9 @@ static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDispl
|
||||
if(wmWindow == NULL)
|
||||
return;
|
||||
|
||||
char* wmName = (char*) x11GetProperty(data, display, *wmWindow, "_NET_WM_NAME");
|
||||
if(wmName == NULL)
|
||||
wmName = (char*) x11GetProperty(data, display, *wmWindow, "WM_NAME");
|
||||
char* wmName = (char*) x11GetProperty(data, display, *wmWindow, "WM_NAME");
|
||||
if(!ffStrSet(wmName))
|
||||
wmName = (char*) x11GetProperty(data, display, *wmWindow, "_NET_WM_NAME");
|
||||
|
||||
if(ffStrSet(wmName))
|
||||
ffStrbufSetS(&result->wmProcessName, wmName);
|
||||
@@ -62,6 +64,16 @@ static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDispl
|
||||
data->ffXFree(wmWindow);
|
||||
}
|
||||
|
||||
static void x11FetchServerVendor(X11PropertyData* data, Display* display, FFDisplayServerResult* result)
|
||||
{
|
||||
const char* serverVendor = data->ffXServerVendor(display);
|
||||
if (serverVendor && !ffStrEquals(serverVendor, "The X.Org Foundation")) {
|
||||
ffStrbufSetS(&result->wmProtocolName, serverVendor);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
typedef struct XrandrData
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(XInternAtom)
|
||||
@@ -305,8 +317,10 @@ const char* ffdsConnectXrandr(FFDisplayServerResult* result)
|
||||
if(data.display == NULL)
|
||||
return "XOpenDisplay() failed";
|
||||
|
||||
if(propertyDataInitialized && ScreenCount(data.display) > 0)
|
||||
if(propertyDataInitialized && ScreenCount(data.display) > 0) {
|
||||
x11DetectWMFromEWMH(&propertyData, data.display, result);
|
||||
x11FetchServerVendor(&propertyData, data.display, result);
|
||||
}
|
||||
|
||||
data.result = result;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/dns/option.h"
|
||||
|
||||
const char* ffDetectDNS(FFDNSOptions* options, FFlist* results /* list of FFstrbuf */);
|
||||
|
||||
@@ -37,7 +37,7 @@ const char* ffDetectDNS(FFDNSOptions* options, FFlist* results)
|
||||
return "GetAdaptersAddresses() failed";
|
||||
}
|
||||
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteIfIndex();
|
||||
uint32_t defaultRouteIfIndex = ffNetifGetDefaultRouteV4()->ifIndex;
|
||||
// Iterate through all of the adapters
|
||||
for (IP_ADAPTER_ADDRESSES* adapter = adapter_addresses; adapter; adapter = adapter->Next)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/editor/option.h"
|
||||
|
||||
typedef struct FFEditorResult
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user