mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 09:58:03 +02:00
Compare commits
432 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a2bf4e0ac | |||
| 662f5127fa | |||
| fb9117553b | |||
| 9f24e4363f | |||
| 084f9294f2 | |||
| a9f1f9a647 | |||
| 0aed89036b | |||
| df15bbc5f2 | |||
| e6b0bd3817 | |||
| 11cd7153a2 | |||
| f8bc1cb605 | |||
| 8b8eb6f290 | |||
| 056fe21ee2 | |||
| cb0a88df22 | |||
| 298c0431c3 | |||
| 448de9afa5 | |||
| 9401a4b9ad | |||
| ea92ad3785 | |||
| 7aaad5e03e | |||
| 645bf5c839 | |||
| 7638e0e4a1 | |||
| 302b8a7b1b | |||
| dbb9d8a660 | |||
| c51a164042 | |||
| 6b8a62da6e | |||
| 578ca23e75 | |||
| 2e73a90835 | |||
| cc6273fecc | |||
| e63b777916 | |||
| 907567f511 | |||
| e0fd7308be | |||
| b761034aae | |||
| 04d6b1453d | |||
| 11d1754686 | |||
| 25e84decff | |||
| 7d665b203f | |||
| ac62442798 | |||
| 758f96de60 | |||
| db623b9c86 | |||
| c353bf3c96 | |||
| 338b552499 | |||
| 5d73cc1232 | |||
| faddef7a3b | |||
| 2d9bbc8049 | |||
| 64afaa07e7 | |||
| 5cf3ab23b0 | |||
| 3fe926d3a0 | |||
| f71bb682de | |||
| 904f860f3c | |||
| 8f15c9604c | |||
| ff28f5807b | |||
| 6a317366d7 | |||
| dc3e4a2d18 | |||
| 46c4a71ba3 | |||
| f0759acd11 | |||
| 96c7c2966d | |||
| 554e7bce4a | |||
| 70377a8afd | |||
| 51bc6d421a | |||
| be0756f8ba | |||
| 71a2cb4e1b | |||
| 2eba761bed | |||
| 4b5e1a816b | |||
| a92e4b2d67 | |||
| a32404ba98 | |||
| 0a792e4935 | |||
| 05108977e8 | |||
| 25353261d0 | |||
| 4b517263d0 | |||
| 98a65966e7 | |||
| 32dcf9487f | |||
| e3a698f7b1 | |||
| 1631f74700 | |||
| 78c6d71049 | |||
| 0b9ecdeade | |||
| 185a9211f1 | |||
| 24459b2fbf | |||
| 88c8dcb3e8 | |||
| f3a8fedf0a | |||
| 6b8b7c1a62 | |||
| af26828f91 | |||
| f4c43abbf7 | |||
| e84739bff0 | |||
| 66aad0e4f1 | |||
| 77c43c0214 | |||
| 31ae7a642a | |||
| 1bbb21486c | |||
| 316d8ddf9b | |||
| 5d8c21a5ca | |||
| 240ba5c00c | |||
| 554184ec72 | |||
| 7a055a2254 | |||
| 0a807ac1a3 | |||
| 4d831c8c73 | |||
| e6e78a7aae | |||
| 09bef5f41d | |||
| e394efdd85 | |||
| c10b652a2e | |||
| 1594a69d6c | |||
| 9b1e318bd1 | |||
| e292bf1dee | |||
| 55a0c6e97d | |||
| 8b8e4a40a4 | |||
| 8be070998f | |||
| 093f56a03d | |||
| bd9744c27c | |||
| adc25f4420 | |||
| 229fe7c7bf | |||
| 5d571752ae | |||
| 512ddfae6b | |||
| 7b689f94df | |||
| 9eed149b09 | |||
| 0f5d321df8 | |||
| 4e84094fd8 | |||
| 7b9fce0189 | |||
| 9ab5c33008 | |||
| 613b1d63f1 | |||
| 8c86cafec7 | |||
| 4098cf51b3 | |||
| bfc23232f8 | |||
| 483fba44dc | |||
| 851751f99d | |||
| 3e86130ddd | |||
| 350ffced13 | |||
| cdcdb78b97 | |||
| 2ae9d01200 | |||
| e95393750b | |||
| de9229697a | |||
| 9d23d28594 | |||
| 57a4b9b6ed | |||
| ef3989d18d | |||
| 3079b44f63 | |||
| 403900639c | |||
| 0bb5b4cc9c | |||
| 1180eb55a4 | |||
| f0e9caaf04 | |||
| 2c22c3b0c0 | |||
| e9065e15e8 | |||
| 9e7816069b | |||
| 82cdc4cd91 | |||
| 822ddc6dc6 | |||
| 8bd171a9ff | |||
| 509d6bf30c | |||
| ab8a13b2d3 | |||
| 3bcdcc5dbf | |||
| 38f4215a94 | |||
| e3eec3f62a | |||
| e025f28cdc | |||
| 3ece4e3b4d | |||
| 6d72a32d1d | |||
| 45be29bad3 | |||
| 6f5e618341 | |||
| 1abfa70237 | |||
| baaeef5ab5 | |||
| 8eafec479e | |||
| 5f9e7c799a | |||
| aeb1722eb9 | |||
| de18a07938 | |||
| 88147f80ac | |||
| 505ff6ff65 | |||
| 390549394d | |||
| f7e7d54c16 | |||
| 5e068d22c8 | |||
| b77646f23e | |||
| aa40366a49 | |||
| a64a82f215 | |||
| 0a4d6220e9 | |||
| 6b037c595f | |||
| f628f5c382 | |||
| cf713e32e1 | |||
| 7d08f81075 | |||
| 8822653335 | |||
| 75ff054255 | |||
| c51cc8ce6b | |||
| 44e23412b5 | |||
| 59742bca00 | |||
| 303edb97ce | |||
| 37ab380a6f | |||
| a06e245c34 | |||
| 5de432b083 | |||
| 817285ac01 | |||
| 8687505505 | |||
| 34c34d25c4 | |||
| 21b15ee944 | |||
| 8e0a65126e | |||
| 54d8b0a95d | |||
| 48fc72e95c | |||
| e3d6a85888 | |||
| 7d92da8829 | |||
| 2f3a361b1f | |||
| ac71f21e6c | |||
| 8d5316f6aa | |||
| 1242fda66f | |||
| 5a2b618d27 | |||
| d836d7569f | |||
| 8a412e6823 | |||
| 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 | |||
| 02aafbd7f4 | |||
| 72da8150bd | |||
| aca2b5336d | |||
| c79b67efc1 | |||
| 30af91ce8e | |||
| 6c56348e54 | |||
| 531b25dc2f | |||
| 8c6dc34654 | |||
| cf2034b93e | |||
| f7db03b8c4 | |||
| 8647e366f9 | |||
| 1bf41d68f9 |
@@ -0,0 +1,3 @@
|
||||
github: LinusDierheimer
|
||||
ko_fi: carterli
|
||||
custom: https://paypal.me/zhangsongcui
|
||||
@@ -36,3 +36,5 @@ body:
|
||||
required: true
|
||||
- label: The ASCII art contains color codes, or the color codes are available in `os-release`
|
||||
required: true
|
||||
- label: The ASCII art contains no internal paddings (spaces at the start and the end of lines)
|
||||
required: true
|
||||
|
||||
+174
-299
@@ -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,13 +32,13 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_XFCONF=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
@@ -58,17 +61,24 @@ jobs:
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
linux-amd64:
|
||||
name: Linux-amd64
|
||||
runs-on: ubuntu-22.04
|
||||
linux-hosts:
|
||||
name: Linux-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
runs-on: ubuntu-22.04
|
||||
- arch: aarch64
|
||||
runs-on: ubuntu-22.04-arm
|
||||
outputs:
|
||||
ffversion: ${{ steps.ffversion.outputs.ffversion }}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -79,26 +89,31 @@ jobs:
|
||||
- name: cat /proc/cpuinfo
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: add gcc-13 repo
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 g++-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libchafa-dev directx-headers-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick --ignore-dependencies
|
||||
|
||||
- name: Initialize CodeQL
|
||||
if: matrix.arch == 'amd64'
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: c
|
||||
|
||||
- name: configure project
|
||||
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: CC=gcc-13 CXX=g++-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
- name: perform CodeQL analysis
|
||||
if: matrix.arch == 'amd64'
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
- name: list features
|
||||
@@ -123,21 +138,33 @@ jobs:
|
||||
id: ffversion
|
||||
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: polyfill glibc
|
||||
run: |
|
||||
wget https://github.com/CarterLi/polyfill-glibc/releases/download/v0.0.1/polyfill-glibc-${{ matrix.arch }} -O polyfill-glibc
|
||||
chmod +x polyfill-glibc
|
||||
strip fastfetch && ./polyfill-glibc fastfetch --target-glibc=2.17
|
||||
strip flashfetch && ./polyfill-glibc flashfetch --target-glibc=2.17
|
||||
echo 'set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-polyfilled")' >> CPackConfig.cmake
|
||||
echo 'set(CPACK_PACKAGE_RELOCATABLE OFF)' >> CPackConfig.cmake
|
||||
echo 'set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.17)")' >> CPackConfig.cmake
|
||||
echo 'set(CPACK_RPM_SPEC_MORE_DEFINE "%global __os_install_post %{nil}")' >> CPackConfig.cmake
|
||||
cpack -V
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-linux-amd64
|
||||
name: fastfetch-linux-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-aarch64:
|
||||
name: Linux-aarch64
|
||||
runs-on: ubuntu-22.04-arm
|
||||
linux-i686:
|
||||
name: Linux-i686
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -148,20 +175,29 @@ jobs:
|
||||
- name: cat /proc/cpuinfo
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: add gcc-13 repo
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
|
||||
- name: cmake version
|
||||
run: cmake --version
|
||||
|
||||
- name: configure project
|
||||
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_DIRECTX_HEADERS=Off .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
- name: check deb package
|
||||
run: dpkg -I fastfetch-*.deb
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
@@ -180,14 +216,10 @@ jobs:
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: get fastfetch version
|
||||
id: ffversion
|
||||
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-linux-aarch64
|
||||
name: fastfetch-linux-i686
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-armv7l:
|
||||
@@ -198,7 +230,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
|
||||
@@ -209,12 +241,13 @@ jobs:
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y wget
|
||||
# CMake installed by apt has bug `list sub-command REMOVE_ITEM requires two or more arguments`
|
||||
wget --no-check-certificate https://apt.kitware.com/ubuntu/pool/main/c/cmake/{cmake_3.29.2-0kitware1ubuntu20.04.1_armhf.deb,cmake-data_3.29.2-0kitware1ubuntu20.04.1_all.deb}
|
||||
dpkg -i *.deb
|
||||
apt-get install -y make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
apt-get update && apt-get install -y software-properties-common ca-certificates gpg curl
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
|
||||
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
|
||||
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -237,7 +270,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
|
||||
@@ -249,8 +282,8 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y wget
|
||||
apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -265,27 +298,35 @@ jobs:
|
||||
name: fastfetch-linux-armv6l
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-riscv64:
|
||||
name: Linux-riscv64
|
||||
runs-on: ubuntu-24.04
|
||||
linux-vms:
|
||||
name: Linux-${{ matrix.arch }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: riscv64
|
||||
- arch: ppc64le
|
||||
- arch: s390x
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: riscv64
|
||||
arch: ${{ matrix.arch }}
|
||||
distro: ubuntu22.04
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libddcutil-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
apt-get update && apt-get install -y software-properties-common
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_DIRECTX_HEADERS=Off -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -297,84 +338,14 @@ jobs:
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-linux-riscv64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-ppc64le:
|
||||
name: Linux-ppc64le
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: ppc64le
|
||||
distro: ubuntu20.04
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-linux-ppc64le
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-s390x:
|
||||
name: Linux-s390x
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: s390x
|
||||
distro: ubuntu20.04
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-linux-s390x
|
||||
name: fastfetch-linux-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
musl-amd64:
|
||||
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
|
||||
@@ -383,7 +354,7 @@ jobs:
|
||||
run: |
|
||||
cat /etc/alpine-release
|
||||
uname -a
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
shell: alpine.sh --root {0}
|
||||
|
||||
- name: build
|
||||
@@ -408,15 +379,22 @@ jobs:
|
||||
name: fastfetch-musl-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
macos-amd64:
|
||||
name: macOS-amd64
|
||||
runs-on: macos-13
|
||||
macos-hosts:
|
||||
name: macOS-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
runs-on: macos-15-intel
|
||||
- arch: aarch64
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -452,54 +430,7 @@ jobs:
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-macos-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
macos-aarch64:
|
||||
name: macOS-aarch64
|
||||
runs-on: macos-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
|
||||
- name: install required packages
|
||||
run: |
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
- name: run fastfetch
|
||||
run: time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
|
||||
- name: run fastfetch --format json
|
||||
run: time ./fastfetch -c presets/ci.jsonc --format json
|
||||
|
||||
- name: run flashfetch
|
||||
run: time ./flashfetch
|
||||
|
||||
- name: print dependencies
|
||||
run: otool -L fastfetch
|
||||
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-macos-aarch64
|
||||
name: fastfetch-macos-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
sunos-amd64:
|
||||
@@ -507,7 +438,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 +446,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 +475,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
|
||||
@@ -556,7 +488,7 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg update
|
||||
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa
|
||||
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -580,7 +512,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
|
||||
@@ -592,8 +524,9 @@ jobs:
|
||||
version: '7.7'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
sudo pkg_add -u
|
||||
sudo pkg_add -r llvm-19.1.7p3 cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
|
||||
CC=clang-19 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -616,7 +549,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,8 +561,8 @@ 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
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
|
||||
CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -647,13 +580,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
|
||||
@@ -662,10 +594,10 @@ jobs:
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update
|
||||
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf
|
||||
pkg install -y llvm cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf
|
||||
|
||||
run: |
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
env CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -688,35 +620,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 +630,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
|
||||
@@ -744,37 +647,50 @@ jobs:
|
||||
name: fastfetch-haiku-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
windows-amd64:
|
||||
name: Windows-amd64
|
||||
runs-on: windows-latest
|
||||
windows-hosts:
|
||||
name: Windows-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
runs-on: windows-latest
|
||||
msystem: CLANG64
|
||||
msystem-lower: clang64
|
||||
msys-arch: x86_64
|
||||
- arch: aarch64
|
||||
runs-on: windows-11-arm
|
||||
msystem: CLANGARM64
|
||||
msystem-lower: clangarm64
|
||||
msys-arch: aarch64
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: CLANG64
|
||||
msystem: ${{ matrix.msystem }}
|
||||
update: true
|
||||
install: git mingw-w64-clang-x86_64-7zip mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-vulkan-headers mingw-w64-clang-x86_64-opencl-icd mingw-w64-clang-x86_64-opencl-headers mingw-w64-clang-x86_64-cppwinrt mingw-w64-clang-x86_64-imagemagick
|
||||
install: git mingw-w64-clang-${{ matrix.msys-arch }}-7zip mingw-w64-clang-${{ matrix.msys-arch }}-cmake mingw-w64-clang-${{ matrix.msys-arch }}-clang mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-loader mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-headers mingw-w64-clang-${{ matrix.msys-arch }}-opencl-icd mingw-w64-clang-${{ matrix.msys-arch }}-opencl-headers mingw-w64-clang-${{ matrix.msys-arch }}-cppwinrt mingw-w64-clang-${{ matrix.msys-arch }}-imagemagick mingw-w64-clang-${{ matrix.msys-arch }}-chafa
|
||||
|
||||
- name: print msys version
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: env PKG_CONFIG_PATH=/clang64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --verbose -j4
|
||||
|
||||
- name: copy necessary dlls
|
||||
run: cp /clang64/bin/{OpenCL,vulkan-1}.dll .
|
||||
run: cp /${{ matrix.msystem-lower }}/bin/{OpenCL,vulkan-1}.dll .
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
@@ -794,102 +710,61 @@ jobs:
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: create zip archive
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-amd64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: create 7z archive
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-amd64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload artifacts
|
||||
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
id: upload-unsigned-artifact
|
||||
name: upload artifacts for signing
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-windows-amd64
|
||||
path: ./fastfetch-windows-amd64.*
|
||||
name: fastfetch-windows-${{ matrix.arch }}
|
||||
path: |
|
||||
*.dll
|
||||
fastfetch.exe
|
||||
flashfetch.exe
|
||||
|
||||
windows-aarch64:
|
||||
name: Windows-aarch64
|
||||
runs-on: windows-11-arm
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
name: submit signing request
|
||||
uses: signpath/github-action-submit-signing-request@v1
|
||||
with:
|
||||
msystem: CLANGARM64
|
||||
update: true
|
||||
install: git mingw-w64-clang-aarch64-7zip mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-vulkan-loader mingw-w64-clang-aarch64-vulkan-headers mingw-w64-clang-aarch64-opencl-icd mingw-w64-clang-aarch64-opencl-headers mingw-w64-clang-aarch64-cppwinrt mingw-w64-clang-aarch64-imagemagick
|
||||
|
||||
- name: print msys version
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: env PKG_CONFIG_PATH=/clangarm64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --verbose -j4
|
||||
|
||||
- name: copy necessary dlls
|
||||
run: cp /clangarm64/bin/{OpenCL,vulkan-1}.dll .
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
- name: run fastfetch
|
||||
run: time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
|
||||
- name: run fastfetch --format json
|
||||
run: time ./fastfetch -c presets/ci.jsonc --format json
|
||||
|
||||
- name: run flashfetch
|
||||
run: time ./flashfetch
|
||||
|
||||
- name: print dependencies
|
||||
run: ldd fastfetch
|
||||
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
|
||||
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
|
||||
project-slug: 'fastfetch'
|
||||
signing-policy-slug: ${{ github.ref == 'refs/heads/master' && 'release-signing' || 'test-signing' }}
|
||||
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: '.'
|
||||
|
||||
- name: create zip archive
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-aarch64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: create 7z archive
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-aarch64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload artifacts
|
||||
- name: upload true artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-windows-aarch64
|
||||
path: ./fastfetch-windows-aarch64.*
|
||||
name: fastfetch-windows-${{ matrix.arch }}
|
||||
path: ./fastfetch-windows-${{ matrix.arch }}.*
|
||||
overwrite: true
|
||||
|
||||
release:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- linux-amd64
|
||||
- linux-aarch64
|
||||
- linux-hosts
|
||||
- linux-i686
|
||||
- linux-armv7l
|
||||
- linux-armv6l
|
||||
- linux-riscv64
|
||||
- linux-ppc64le
|
||||
- linux-s390x
|
||||
- linux-vms
|
||||
- musl-amd64
|
||||
- macos-amd64
|
||||
- macos-aarch64
|
||||
- macos-hosts
|
||||
- freebsd-amd64
|
||||
- openbsd-amd64
|
||||
- netbsd-amd64
|
||||
- dragonfly-amd64
|
||||
- sunos-amd64
|
||||
- haiku-amd64
|
||||
- windows-amd64
|
||||
- windows-aarch64
|
||||
- windows-hosts
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -900,29 +775,29 @@ jobs:
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
- name: download artifacts
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: actions/download-artifact@v4
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: actions/download-artifact@v5
|
||||
|
||||
- name: create release
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: ${{ needs.linux-amd64.outputs.ffversion }}
|
||||
tag: ${{ needs.linux-hosts.outputs.ffversion }}
|
||||
commit: ${{ github.sha }}
|
||||
artifactErrorsFailBuild: true
|
||||
artifacts: fastfetch-*/fastfetch-*
|
||||
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details."
|
||||
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-hosts.outputs.ffversion }}/CHANGELOG.md) for details."
|
||||
|
||||
- name: download source tarballs
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
run: |
|
||||
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-amd64.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
|
||||
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-hosts.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
|
||||
ls fastfetch-*/*
|
||||
|
||||
- name: generate release notes
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
run: |
|
||||
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
|
||||
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-hosts.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
|
||||
echo -e "\n---\n\n<details><summary>SHA256SUMs</summary><br>\n\n\`\`\`" >> fastfetch-release-notes.md
|
||||
sha256sum fastfetch-*/* >> fastfetch-release-notes.md
|
||||
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
|
||||
@@ -931,10 +806,10 @@ jobs:
|
||||
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
|
||||
|
||||
- name: update release body
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: ${{ needs.linux-amd64.outputs.ffversion }}
|
||||
tag: ${{ needs.linux-hosts.outputs.ffversion }}
|
||||
commit: ${{ github.sha }}
|
||||
bodyFile: fastfetch-release-notes.md
|
||||
allowUpdates: true
|
||||
|
||||
+335
@@ -1,3 +1,338 @@
|
||||
# 2.55.0
|
||||
|
||||
Changes:
|
||||
* Commands are now executed in parallel by default to improve performance (#2045, Command)
|
||||
* This behavior can be disabled in the config file with `"parallel": false` if it causes problems with certain scripts
|
||||
* Folder/filesystem hiding is moved to the detection stage; hidden entries are no longer probed, improving performance (#2043, Disk)
|
||||
|
||||
Features:
|
||||
* Adds `command.parallel` and `command.useStdErr` config options (Command)
|
||||
* `parallel`: set to `false` to disable parallel execution (see Changes above)
|
||||
* `useStdErr`: set to `true` to use stderr output instead of stdout
|
||||
* Adds the command-line flag `--dynamic-interval <interval-in-ms>` to enable dynamic output auto-refresh (#2041)
|
||||
* Due to internal limitations, some modules do not support dynamic updates (notably Display and Media)
|
||||
* Adds support for using the current playing media's cover art as a logo source (Media / Logo)
|
||||
* Usage: `"logo": { "type": "<image-protocol>", "source": "media-cover" }` in JSON config; or `--<image-protocol> media-cover` in command line
|
||||
* Supports local sources only
|
||||
* Adds native GPU detection support on OpenBSD and NetBSD (instead of depending on `libpciaccess`) (GPU)
|
||||
* No functional changes
|
||||
* Root privileges are required to access PCI config space on OpenBSD (as always)
|
||||
* Adds GPU detection support on GNU/Hurd (GPU)
|
||||
* Requires building with `libpciaccess`
|
||||
* Shows Debian point release on Raspberry Pi OS (#2032, OS, Linux)
|
||||
* Adds `Brush` shell version detection (Shell)
|
||||
* Improves Mac family detection via prefix matching (Host)
|
||||
|
||||
Bugfixes:
|
||||
* Ignores `run-parts` during terminal/shell detection (#2048, Terminal / Shell, Linux)
|
||||
* Fixes fish version detection when `LC_ALL` is set (#2014, Shell, Linux)
|
||||
* Hides the module when no desktop icons are found (#2023, Icons, Windows)
|
||||
* Skips auxiliary display controllers to prevent the module from reporting duplicate entries (#2034, GPU, Linux)
|
||||
* Refines Apple rpath handling; fixes building for the Homebrew version on macOS (#1998, CMake)
|
||||
|
||||
Logos:
|
||||
* Adds Vincent OS and MacaroniOS
|
||||
|
||||
# 2.54.0
|
||||
|
||||
Windows binaries in Release page are now signed by SignPath.
|
||||
|
||||
Changes:
|
||||
* Moves macOS and Windows design language detection from the DE module to the Theme module
|
||||
|
||||
Features:
|
||||
* Adds `--json` and `-j` command line flags as a shortcut for `--format json`
|
||||
* Various improvements to the OS module (OS)
|
||||
* Displays point releases for Debian
|
||||
* Displays code names for Ubuntu
|
||||
* Displays build ID for macOS
|
||||
* Displays code names for Windows (previously shown in the Kernel module)
|
||||
* Adds basic support for Wine (Windows)
|
||||
* Adds basic support for hppa and sh architectures (CPU, Linux)
|
||||
* Improves T-Head SoC name detection from the device tree (#1997, CPU, Linux)
|
||||
* Supports glob patterns in `Disk.hideFolders` (Disk)
|
||||
* For example, `/boot/*` will match both `/boot/efi` and `/boot/firmware`
|
||||
* Adds brightness-level detection for external monitor support on Intel macOS (Brightness, macOS)
|
||||
* Adds configurable spacing between icon and text in keys
|
||||
* `display.key.type: "both-N"` where N is `0-4`
|
||||
* Useful for non-monospaced Nerd Fonts
|
||||
* Adds detection support for modern Samsung Exynos SoCs (CPU, Android)
|
||||
* Adds a new CMake option `-DENABLE_WORDEXP=<ON|OFF>` to enable or disable using `wordexp(3)` for acquiring logo file paths (`logo.source`)
|
||||
* Enabled by default for compatibility
|
||||
* Disabling this option reverts to using `glob(3)`, which is less functional but more secure
|
||||
|
||||
Bugfixes:
|
||||
* Avoids integer overflow when calculating swap size (#1988, Swap, Windows)
|
||||
* Trims whitespace from full user name (Title, macOS)
|
||||
* Fixes default font size for Ghostty (#1986, TerminalFont, Linux)
|
||||
* Works around an issue that could report impossibly high memory usage in rare cases (#1988, Memory, Linux)
|
||||
* Fixes incorrect glibc dependency in polyfilled DEB packages (#1983, Linux)
|
||||
* Fixes corrupted binaries in polyfilled RPM packages (#1990, Linux)
|
||||
* Fixes crashes on ancient Android kernels (#1993, Disk, Android)
|
||||
* Fixes incorrect usage of `glob(3)` (OpenBSD)
|
||||
* Prefers resolutions reported by RandR mode info, fixing incorrect resolutions on XFCE when DPI scaling is enabled (Display, Linux)
|
||||
* Various code cleanups and minor fixes
|
||||
|
||||
Logos:
|
||||
* Adds secureblue, PrismLinux, EmperorOS and Zraxyl
|
||||
* Updates T2
|
||||
|
||||
# 2.53.0
|
||||
|
||||
Changes:
|
||||
* JSON property `length` in `Separator` module has been renamed to `times` for clarity (Separator)
|
||||
|
||||
Features:
|
||||
* Adds IPv6 type selection (#1459, LocalIP)
|
||||
* For example: `{ "type": "localip", "showIpv6": "ula" /* Show ULA only */ }`
|
||||
* Adds more ARM CPU part IDs (CPU, Linux)
|
||||
* Improves Ghostty font config parsing with fallback font detection (#1967, TerminalFont)
|
||||
* Replaces statx(2) call with syscall(2) for better compatibility (Disk, Linux)
|
||||
* Allows array input for disk folder and filesystem options (Disk)
|
||||
* For example: `{ "type": "disk", "folders": ["/", "/home"] }`
|
||||
* Adds support for ignoring input devices by name prefix (#1950, Keyboard / Mouse / Gamepad)
|
||||
* For example: `{ "type": "keyboard", "ignores": ["Apple ", "Corsair "] }`
|
||||
* Adds support for (B)SSID detection on macOS Tahoe (Wifi, macOS)
|
||||
* Please don't expect it to work on later macOS versions
|
||||
* Improves Ubuntu flavor detection (#1975, OS, Linux)
|
||||
* Refines ARMv8.4-A detection to require LSE2 (CPU, Windows)
|
||||
* Detects the latest Dimensity & Snapdragon SoC names (CPU, Android)
|
||||
|
||||
Bugfixes:
|
||||
* Handles zero temperature data (#1960, CPU, Windows)
|
||||
* Fixes `dlopen libzfs.so failed` error on Proxmox 9 (#1973, Zpool, Linux)
|
||||
|
||||
Logos:
|
||||
* Removes Starry Linux
|
||||
* Adds TempleOS
|
||||
* Updates ObsidianOS
|
||||
|
||||
# 2.52.0
|
||||
|
||||
Changes:
|
||||
* New optional build dependencies on Android
|
||||
* main: chafa dbus glib imagemagick libelf libxcb libxrandr pulseaudio zlib
|
||||
* x11: dconf (Optional)
|
||||
* Dependency on `libxfconf` is removed. XFCE related detection now uses `libdbus` instead (Linux)
|
||||
* The default format of `Display` module is updated to `{width}x{height} @ {scale-factor}x in {inch}", {refresh-rate} Hz`
|
||||
* Replaced scaled resolution with scale factor for shorter texts and avoiding potential confusion.
|
||||
|
||||
Bugfixes:
|
||||
* Fixes linking on 32-bit Android (#1939)
|
||||
* Skips network interfaces without IPs unless MAC address is requested (#1949, LocalIP)
|
||||
* Fixes unexpected padding when setting `logo.width` with chafa logos (#1947, Logo)
|
||||
* Regression from v2.51.0
|
||||
* Improves Wallpaper detection on XFCE4 (Wallpaper, Linux)
|
||||
* Ignores process `Relay(xxx)` when detecting terminal on WSL2 (Terminal, Linux)
|
||||
|
||||
Features:
|
||||
* Enables X11-related info (i.e., WM/DE) detection on Android (Global, Android)
|
||||
* This requires many dependencies. See above.
|
||||
* Adds scale factors detection for X11 (Display, Linux)
|
||||
* X11 doesn't natively report scale factor as Wayland does. Instead, Fastfetch tries to detect `Xft.dpi` (DPI used by X FreeType for scaling fonts), which is usually set by the WM when DPI scaling is enabled.
|
||||
* It's not always accurate. For example, XFCE4 has a separate config for text scaling, which is unaffected by the global DPI scaling setting.
|
||||
* Adds `display.fraction.trailingZeros: [always|never]` option for fraction formatting
|
||||
* The default value of `display.fraction.ndigits` is changed from `-1` (unlimited) to `2` for usability.
|
||||
* Used for displaying scale factor in Display module mentioned above, alongside other places for printing raw fraction numbers.
|
||||
* Informs users that module-specific CLI options are no longer supported and provide guidance for transitioning to JSON config
|
||||
* Adds CPU name detection support for IA64 (CPU, Linux)
|
||||
* Support Btrfs allocation profile detection (#1941, Btrfs, Linux)
|
||||
|
||||
# 2.51.1
|
||||
|
||||
Bugfixes:
|
||||
* Fix building on macOS 14 or older; no functional changes (CPU, macOS)
|
||||
|
||||
# 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:
|
||||
* Add support for detecting Openbox WM version (WM, Linux)
|
||||
* Improve reliability of child process spawning on Windows (Windows)
|
||||
* Add a new option `--packages-combined`, which combines related package managers into single counts (#1851, Packages)
|
||||
* For example: if you have both `flatpak-system` and `flatpak-user` packages installed, they will be combined into a single `flatpak` count with `--packages-combined` enabled.
|
||||
* Add `modules[n].condition` to conditionally enable modules on different platforms
|
||||
* Useful when sharing configuration files across platforms
|
||||
* For example:
|
||||
```jsonc
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "This string will be printed on Intel macOS only",
|
||||
"condition": {
|
||||
"system": "macOS", // Can be an array, optional
|
||||
"arch": "x86_64" // Can be an array, optional too
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bugfixes:
|
||||
* Revert the change of `posix_spawn` in v2.48.0 for Android and OpenBSD (Android / OpenBSD)
|
||||
* Fix completion for Android 7 (Required by Termux)
|
||||
|
||||
# 2.48.0
|
||||
|
||||
Features:
|
||||
|
||||
+197
-84
@@ -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.0
|
||||
VERSION 2.55.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -9,6 +9,17 @@ project(fastfetch
|
||||
|
||||
set(PROJECT_LICENSE "MIT license")
|
||||
|
||||
if(DEFINED CMAKE_SYSTEM_PROCESSOR_OVERRIDE) # Used by github actions for i686 build
|
||||
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR_OVERRIDE} CACHE INTERNAL "")
|
||||
endif()
|
||||
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" CMAKE_SYSTEM_PROCESSOR)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "amd64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
|
||||
endif()
|
||||
message(STATUS "Build for system processor: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
|
||||
###################
|
||||
# Target Platform #
|
||||
###################
|
||||
@@ -32,6 +43,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,34 +69,33 @@ 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 ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID 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 ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR Haiku 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 ANDROID 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 ANDROID 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)
|
||||
cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "GNU" OFF)
|
||||
|
||||
option(ENABLE_ZLIB "Enable zlib" ON)
|
||||
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
|
||||
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
|
||||
option(ENABLE_LTO "Enable link-time optimization in release mode if supported" ON)
|
||||
@@ -94,6 +106,7 @@ option(IS_MUSL "Build with musl libc" OFF) # Used by Github Actions
|
||||
option(INSTALL_LICENSE "Install license into /usr/share/licenses" ON)
|
||||
option(ENABLE_EMBEDDED_PCIIDS "Embed pci.ids into fastfetch, requires `python`" OFF)
|
||||
option(ENABLE_EMBEDDED_AMDGPUIDS "Embed amdgpu.ids into fastfetch, requires `python`" OFF)
|
||||
option(ENABLE_WORDEXP "Enable using of wordexp(3) if available, instead of glob(3)" ON)
|
||||
|
||||
set(BINARY_LINK_TYPE_OPTIONS dlopen dynamic static)
|
||||
set(BINARY_LINK_TYPE dlopen CACHE STRING "How to link fastfetch")
|
||||
@@ -351,10 +364,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,15 +377,19 @@ 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
|
||||
src/detection/cpu/cpu.c
|
||||
src/detection/cpuusage/cpuusage.c
|
||||
src/detection/command/command.c
|
||||
src/detection/disk/disk.c
|
||||
src/detection/diskio/diskio.c
|
||||
src/detection/displayserver/displayserver.c
|
||||
@@ -471,7 +489,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
|
||||
@@ -510,6 +527,7 @@ if(LINUX)
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/diskio/diskio_linux.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
src/detection/displayserver/linux/drm.c
|
||||
src/detection/displayserver/linux/wayland/wayland.c
|
||||
src/detection/displayserver/linux/wayland/global-output.c
|
||||
@@ -545,6 +563,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
|
||||
@@ -569,6 +588,7 @@ if(LINUX)
|
||||
)
|
||||
elseif(ANDROID)
|
||||
list(APPEND LIBFASTFETCH_SRC
|
||||
src/common/dbus.c
|
||||
src/common/io/io_unix.c
|
||||
src/common/netif/netif_linux.c
|
||||
src/common/networking/networking_linux.c
|
||||
@@ -584,7 +604,7 @@ elseif(ANDROID)
|
||||
src/detection/chassis/chassis_nosupport.c
|
||||
src/detection/cpu/cpu_linux.c
|
||||
src/detection/cpucache/cpucache_linux.c
|
||||
src/detection/cursor/cursor_nosupport.c
|
||||
src/detection/cursor/cursor_linux.c
|
||||
src/detection/cpuusage/cpuusage_linux.c
|
||||
src/detection/disk/disk_linux.c
|
||||
src/detection/dns/dns_linux.c
|
||||
@@ -592,10 +612,16 @@ elseif(ANDROID)
|
||||
src/detection/physicalmemory/physicalmemory_nosupport.c
|
||||
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/displayserver/linux/common.c
|
||||
src/detection/displayserver/linux/wmde.c
|
||||
src/detection/displayserver/linux/xcb.c
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_android.c
|
||||
src/detection/host/host_android.c
|
||||
src/detection/icons/icons_nosupport.c
|
||||
src/detection/icons/icons_linux.c
|
||||
src/detection/initsystem/initsystem_linux.c
|
||||
src/detection/keyboard/keyboard_nosupport.c
|
||||
src/detection/libc/libc_android.c
|
||||
@@ -604,29 +630,31 @@ elseif(ANDROID)
|
||||
src/detection/locale/locale_linux.c
|
||||
src/detection/localip/localip_linux.c
|
||||
src/detection/gamepad/gamepad_nosupport.c
|
||||
src/detection/media/media_nosupport.c
|
||||
src/detection/media/media_linux.c
|
||||
src/detection/memory/memory_linux.c
|
||||
src/detection/mouse/mouse_nosupport.c
|
||||
src/detection/netio/netio_linux.c
|
||||
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
|
||||
src/detection/sound/sound_linux.c
|
||||
src/detection/swap/swap_linux.c
|
||||
src/detection/terminalfont/terminalfont_android.c
|
||||
src/detection/terminalfont/terminalfont_linux.c
|
||||
src/detection/terminalshell/terminalshell_linux.c
|
||||
src/detection/terminalsize/terminalsize_linux.c
|
||||
src/detection/theme/theme_nosupport.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_nosupport.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_android.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/de/de_nosupport.c
|
||||
src/detection/wmtheme/wmtheme_nosupport.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_android.c
|
||||
src/detection/zpool/zpool_nosupport.c
|
||||
src/util/platform/FFPlatform_unix.c
|
||||
@@ -658,6 +686,7 @@ elseif(FreeBSD)
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/diskio/diskio_bsd.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
src/detection/displayserver/linux/drm.c
|
||||
src/detection/displayserver/linux/wayland/wayland.c
|
||||
src/detection/displayserver/linux/wayland/global-output.c
|
||||
@@ -752,6 +781,7 @@ elseif(NetBSD)
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/diskio/diskio_nbsd.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
src/detection/displayserver/linux/drm.c
|
||||
src/detection/displayserver/linux/wayland/wayland.c
|
||||
src/detection/displayserver/linux/wayland/global-output.c
|
||||
@@ -765,7 +795,7 @@ elseif(NetBSD)
|
||||
src/detection/displayserver/linux/xcb.c
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_general.c
|
||||
src/detection/gpu/gpu_nbsd.c
|
||||
src/detection/gpu/gpu_pci.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_nbsd.c
|
||||
@@ -834,6 +864,7 @@ elseif(OpenBSD)
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/diskio/diskio_obsd.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
src/detection/displayserver/linux/drm.c
|
||||
src/detection/displayserver/linux/wayland/wayland.c
|
||||
src/detection/displayserver/linux/wayland/global-output.c
|
||||
@@ -848,7 +879,7 @@ elseif(OpenBSD)
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_pci.c
|
||||
src/detection/gpu/gpu_general.c
|
||||
src/detection/gpu/gpu_obsd.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_obsd.c
|
||||
src/detection/lm/lm_nosupport.c
|
||||
@@ -893,7 +924,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 +968,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
|
||||
@@ -944,7 +976,7 @@ elseif(APPLE)
|
||||
src/detection/terminalfont/terminalfont_apple.m
|
||||
src/detection/terminalshell/terminalshell_linux.c
|
||||
src/detection/terminalsize/terminalsize_linux.c
|
||||
src/detection/theme/theme_nosupport.c
|
||||
src/detection/theme/theme_apple.c
|
||||
src/detection/tpm/tpm_apple.c
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
@@ -1005,7 +1037,7 @@ elseif(WIN32)
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/netio/netio_windows.c
|
||||
src/detection/opengl/opengl_windows.c
|
||||
src/detection/os/os_windows.c
|
||||
src/detection/os/os_windows.cpp
|
||||
src/detection/packages/packages_windows.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_windows.c
|
||||
@@ -1014,7 +1046,7 @@ elseif(WIN32)
|
||||
src/detection/terminalfont/terminalfont_windows.c
|
||||
src/detection/terminalshell/terminalshell_windows.c
|
||||
src/detection/terminalsize/terminalsize_windows.c
|
||||
src/detection/theme/theme_nosupport.c
|
||||
src/detection/theme/theme_windows.c
|
||||
src/detection/tpm/tpm_windows.c
|
||||
src/detection/uptime/uptime_windows.c
|
||||
src/detection/users/users_windows.c
|
||||
@@ -1039,7 +1071,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
|
||||
@@ -1061,6 +1093,7 @@ elseif(SunOS)
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
src/detection/diskio/diskio_sunos.c
|
||||
src/detection/displayserver/linux/displayserver_linux.c
|
||||
src/detection/displayserver/linux/common.c
|
||||
src/detection/displayserver/linux/drm.c
|
||||
src/detection/displayserver/linux/wayland/wayland.c
|
||||
src/detection/displayserver/linux/wayland/global-output.c
|
||||
@@ -1186,6 +1219,85 @@ 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/common.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_general.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)
|
||||
@@ -1205,10 +1317,7 @@ endif()
|
||||
include(CheckFunctionExists)
|
||||
check_function_exists(wcwidth HAVE_WCWIDTH)
|
||||
if(NOT HAVE_WCWIDTH)
|
||||
list(APPEND LIBFASTFETCH_SRC src/3rdparty/mk_wcwidch/wcwidth.c)
|
||||
endif()
|
||||
if(LINUX)
|
||||
check_function_exists(statx HAVE_STATX)
|
||||
list(APPEND LIBFASTFETCH_SRC src/util/wcwidth.c)
|
||||
endif()
|
||||
if(NOT WIN32)
|
||||
check_function_exists(pipe2 HAVE_PIPE2)
|
||||
@@ -1232,15 +1341,15 @@ add_library(libfastfetch OBJECT
|
||||
)
|
||||
|
||||
if(yyjson_FOUND)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_USE_SYSTEM_YYJSON)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_USE_SYSTEM_YYJSON=1)
|
||||
target_link_libraries(libfastfetch PUBLIC yyjson::yyjson)
|
||||
# `target_link_libraries(yyjson::yyjson)` sets rpath implicitly
|
||||
else()
|
||||
# Used for dlopen finding dylibs installed by homebrew
|
||||
# `/opt/homebrew/lib` is not on in dlopen search path by default
|
||||
if(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/opt/homebrew/lib -Wl,-rpath,/usr/local/lib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Used for dlopen finding dylibs installed by homebrew
|
||||
# `/opt/homebrew/lib` is not on in dlopen search path by default
|
||||
if(APPLE AND NOT BINARY_LINK_TYPE STREQUAL "dlopen")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,/opt/homebrew/lib -Wl,-rpath,/usr/local/lib")
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
@@ -1309,6 +1418,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)
|
||||
@@ -1321,10 +1434,6 @@ if(FreeBSD OR OpenBSD OR NetBSD)
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if(HAVE_STATX)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_STATX)
|
||||
endif()
|
||||
|
||||
if(HAVE_WCWIDTH)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_WCWIDTH)
|
||||
endif()
|
||||
@@ -1435,10 +1544,6 @@ ff_lib_enable(DBUS
|
||||
"dbus-1"
|
||||
"DBus"
|
||||
)
|
||||
ff_lib_enable(XFCONF
|
||||
"libxfconf-0"
|
||||
"XFConf"
|
||||
)
|
||||
ff_lib_enable(SQLITE3
|
||||
"sqlite3"
|
||||
"SQLite3"
|
||||
@@ -1586,11 +1691,10 @@ elseif(WIN32)
|
||||
PRIVATE "wtsapi32"
|
||||
PRIVATE "imagehlp"
|
||||
PRIVATE "cfgmgr32"
|
||||
PRIVATE "winbrand"
|
||||
PRIVATE "propsys"
|
||||
PRIVATE "secur32"
|
||||
)
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
# WoA only works on Windows 10 or higher
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "mincore"
|
||||
@@ -1633,18 +1737,28 @@ 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)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE -l:libandroid-wordexp.a
|
||||
)
|
||||
else()
|
||||
CHECK_LIBRARY_EXISTS(android-wordexp wordexp "" HAVE_LIBANDROID_WORDEXP)
|
||||
if(HAVE_LIBANDROID_WORDEXP)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "m"
|
||||
)
|
||||
if(ENABLE_WORDEXP)
|
||||
# https://github.com/termux/termux-packages/pull/7056
|
||||
CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC)
|
||||
if(HAVE_LIBANDROID_WORDEXP_STATIC)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE android-wordexp
|
||||
PRIVATE -l:libandroid-wordexp.a
|
||||
)
|
||||
else()
|
||||
CHECK_LIBRARY_EXISTS(android-wordexp wordexp "" HAVE_LIBANDROID_WORDEXP)
|
||||
if(HAVE_LIBANDROID_WORDEXP)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE android-wordexp
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
elseif(Haiku)
|
||||
@@ -1706,13 +1820,17 @@ if(NOT WIN32)
|
||||
if(HAVE_UTMPX)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_UTMPX=1)
|
||||
endif()
|
||||
CHECK_INCLUDE_FILE("wordexp.h" HAVE_WORDEXP)
|
||||
if(HAVE_WORDEXP)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WORDEXP=1)
|
||||
if(ENABLE_WORDEXP)
|
||||
CHECK_INCLUDE_FILE("wordexp.h" HAVE_WORDEXP)
|
||||
if(HAVE_WORDEXP)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WORDEXP=1)
|
||||
message(STATUS "wordexp.h found, wordexp support enabled")
|
||||
else()
|
||||
set(ENABLE_WORDEXP OFF)
|
||||
endif()
|
||||
endif()
|
||||
CHECK_INCLUDE_FILE("glob.h" HAVE_GLOB)
|
||||
if(HAVE_GLOB)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GLOB=1)
|
||||
if(NOT ENABLE_WORDEXP)
|
||||
message(STATUS "wordexp.h not found or disabled, glob used instead")
|
||||
endif()
|
||||
if(ENABLE_THREADS AND CMAKE_USE_PTHREADS_INIT)
|
||||
CHECK_INCLUDE_FILE("pthread_np.h" HAVE_PTHREAD_NP)
|
||||
@@ -1921,11 +2039,6 @@ install(
|
||||
##################
|
||||
|
||||
set(CPACK_GENERATOR "TGZ;ZIP")
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "amd64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
|
||||
endif()
|
||||
if(APPLE)
|
||||
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME) # use macos instead of darwin
|
||||
elseif(IS_MUSL)
|
||||
@@ -1972,7 +2085,7 @@ endif()
|
||||
|
||||
set(CPACK_SET_DESTDIR ON)
|
||||
|
||||
set(CPACK_PACKAGE_CONTACT "Linus Dierheimer <Linus@Dierheimer.de>")
|
||||
set(CPACK_PACKAGE_CONTACT "Carter Li <zhangsongcui@live.cn>")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "\
|
||||
fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way. \
|
||||
It is written mostly in C to achieve much better performance.\
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# Fastfetch
|
||||
|
||||
Fastfetch 是一款类似 neofetch 的系统信息展示工具,主要用 C 编写,强调性能和可定制性。支持 Linux、macOS、Windows 7+、Android、FreeBSD、OpenBSD、NetBSD、DragonFly、Haiku、SunOS。
|
||||
|
||||
示例配置见 presets/examples,更多截图与平台说明见 Wiki。
|
||||
|
||||
## 安装
|
||||
|
||||
Linux(部分):
|
||||
- Debian 13+ / Ubuntu: apt install fastfetch
|
||||
- Arch: pacman -S fastfetch
|
||||
- Fedora: dnf install fastfetch
|
||||
- openSUSE: zypper install fastfetch
|
||||
- Linuxbrew:brew install fastfetch
|
||||
- 各发行版打包状态:https://repology.org/project/fastfetch/versions
|
||||
|
||||
macOS:
|
||||
- Homebrew:brew install fastfetch
|
||||
- MacPorts:sudo port install fastfetch
|
||||
|
||||
Windows:
|
||||
- scoop install fastfetch
|
||||
- choco install fastfetch
|
||||
- winget install fastfetch
|
||||
- MSYS2:pacman -S mingw-w64-<subsystem>-<arch>-fastfetch
|
||||
|
||||
BSD:
|
||||
- FreeBSD:pkg install fastfetch
|
||||
- NetBSD:pkgin in fastfetch
|
||||
- OpenBSD:pkg_add fastfetch
|
||||
|
||||
Android(Termux):
|
||||
- pkg install fastfetch
|
||||
|
||||
Nightly 构建:
|
||||
- https://nightly.link/fastfetch-cli/fastfetch/workflows/ci/dev?preview
|
||||
|
||||
## 源码构建
|
||||
|
||||
基本上是 `cmake . && make`。详见 Wiki:https://github.com/fastfetch-cli/fastfetch/wiki/Building
|
||||
|
||||
## 使用
|
||||
|
||||
- 默认运行:`fastfetch`
|
||||
- 查看所有可用模块示例:`fastfetch -c all.jsonc`
|
||||
- 以 JSON 输出指定模块:`fastfetch -s <module1>[:<module2>] --format json`
|
||||
- 完整命令行帮助:`fastfetch --help`
|
||||
- 生成最小配置:`fastfetch --gen-config [</path/to/config.jsonc>]`
|
||||
- 生成完整配置:`fastfetch --gen-config-full`
|
||||
- 请使用支持 JSON schema 的编辑器(如 VSCode)编辑配置文件!
|
||||
- 如果你连接 Github 有网络困难(智能提示不生效),可将配置文件中的 `$schema` 的值替换为 `https://gitee.com/carterl/fastfetch/raw/dev/doc/json_schema.json`
|
||||
|
||||
## 定制
|
||||
|
||||
- 配置使用 JSONC,语法与选项见 Wiki:https://github.com/fastfetch-cli/fastfetch/wiki/Configuration
|
||||
- 预设示例位于 presets,可用 `-c <filename>` 加载
|
||||
- Logo 选项与图像显示见文档:https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options
|
||||
- 模块格式化(示例,仅显示 GPU 名称):
|
||||
```jsonc
|
||||
{
|
||||
"modules": [
|
||||
{ "type": "gpu", "format": "{name}" }
|
||||
]
|
||||
}
|
||||
```
|
||||
详见:https://github.com/fastfetch-cli/fastfetch/wiki/Format-String-Guide
|
||||
|
||||
## 反馈与支持
|
||||
|
||||
- 使用问题:Discussions https://github.com/fastfetch-cli/fastfetch/discussions
|
||||
- 疑似缺陷:Issues https://github.com/fastfetch-cli/fastfetch/issues(请填写模版)
|
||||
|
||||
## 赞助
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/a36a6501-e8b0-4a10-9061-b9206d12ffba" width="220">
|
||||
@@ -11,6 +11,7 @@
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](https://deepwiki.com/fastfetch-cli/fastfetch)
|
||||
[](README-cn.md)
|
||||
|
||||
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and SunOS.
|
||||
|
||||
@@ -36,7 +37,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 +58,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 +95,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
|
||||
|
||||
@@ -103,6 +104,10 @@ Fastfetch uses JSONC (JSON with comments) for configuration. [See the Wiki for d
|
||||
|
||||
Logos can also be heavily customized; see the [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for more information.
|
||||
|
||||
### WARNING
|
||||
|
||||
Fastfetch supports a `Command` module that can run arbitrary shell commands. If you copy-paste a config file from an untrusted source, it may contain malicious commands that can harm your system or compromise your privacy. Please always review the config file before using it.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Q: Neofetch is good enough. Why do I need fastfetch?
|
||||
@@ -317,6 +322,11 @@ If you find Fastfetch useful, please consider donating.
|
||||
* Current maintainer: [@CarterLi](https://paypal.me/zhangsongcui)
|
||||
* Original author: [@LinusDierheimer](https://github.com/sponsors/LinusDierheimer)
|
||||
|
||||
## Code signing
|
||||
|
||||
* Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
|
||||
* This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it
|
||||
|
||||
## Star History
|
||||
|
||||
Give us a star to show your support!
|
||||
|
||||
+49
-1
@@ -1,3 +1,52 @@
|
||||
fastfetch (2.54.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Fix building on plucky
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 20 Oct 2025 14:27:02 +0800
|
||||
|
||||
fastfetch (2.54.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.54.0
|
||||
* Test independent changelog entries for different Ubuntu releases
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 20 Oct 2025 10:47:02 +0800
|
||||
|
||||
fastfetch (2.53.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.53.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Tue, 23 Sep 2025 09:58:48 +0800
|
||||
|
||||
fastfetch (2.52.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.52.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 05 Sep 2025 14:59:44 +0800
|
||||
|
||||
fastfetch (2.51.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.51.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 29 Aug 2025 08:55:03 +0800
|
||||
|
||||
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
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 17 Jul 2025 16:16:52 +0800
|
||||
|
||||
fastfetch (2.47.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.47.0
|
||||
@@ -399,4 +448,3 @@ fastfetch (2.7.1) jammy; urgency=medium
|
||||
* Initial release.
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Tue, 06 Feb 2024 15:01:11 +0800
|
||||
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ Source: fastfetch
|
||||
Section: universe/utils
|
||||
Priority: optional
|
||||
Maintainer: Carter Li <zhangsongcui@live.cn>
|
||||
Build-Depends: libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libxfconf-0-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
|
||||
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
|
||||
Standards-Version: 4.0.0
|
||||
Homepage: https://github.com/fastfetch-cli/fastfetch
|
||||
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
fastfetch_2.47.0_source.buildinfo universe/utils optional
|
||||
Vendored
+74
-2
@@ -1,4 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# WARNING: DO NOT RUN THIS SCRIPT UNLESS YOU KNOW WHAT YOU ARE DOING.
|
||||
|
||||
debuild -S -i -I
|
||||
dput ppa:zhangsongcui3371/fastfetch ~/fastfetch_*.changes
|
||||
set -euo pipefail
|
||||
|
||||
command -v debuild >/dev/null 2>&1 || { echo "debuild not found. Install devscripts." >&2; exit 1; }
|
||||
command -v dput >/dev/null 2>&1 || { echo "dput not found." >&2; exit 1; }
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
||||
ROOT_DIR="$(cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
|
||||
OUT_DIR="$(dirname "$ROOT_DIR")"
|
||||
PPA="ppa:zhangsongcui3371/fastfetch"
|
||||
CODENAMES=( jammy noble plucky questing resolute )
|
||||
DRY_RUN=0
|
||||
|
||||
if [[ -d "$OUT_DIR/build" ]]; then
|
||||
echo "Output directory exists: $OUT_DIR/build" >&2
|
||||
echo "Please move or delete it before proceeding." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TEMPLATE="$ROOT_DIR/debian/changelog.tpl"
|
||||
CHANGELOG_DEBIAN="$ROOT_DIR/debian/changelog"
|
||||
|
||||
if [[ ! -f "$TEMPLATE" ]]; then
|
||||
echo "Template not found: $TEMPLATE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '#UBUNTU_CODENAME#' "$TEMPLATE"; then
|
||||
echo "Template missing placeholder: #UBUNTU_CODENAME#" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "IMPORTANT: Before proceeding, please ensure that 'debian/changelog.tpl' is up-to-date"
|
||||
echo " with the correct version number, release notes, and maintainer information."
|
||||
echo
|
||||
echo " The template must contain a placeholder like '#UBUNTU_CODENAME#' for the codename."
|
||||
echo
|
||||
read -p "Have you reviewed and updated 'debian/changelog.tpl'? (y/N): " -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
rm -f "$CHANGELOG_DEBIAN"
|
||||
rm -f "$ROOT_DIR/debian/files"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
for codename in "${CODENAMES[@]}"; do
|
||||
echo "==> Publishing distro: $codename"
|
||||
sed "s/#UBUNTU_CODENAME#/${codename}/g" "$TEMPLATE" > "$CHANGELOG_DEBIAN"
|
||||
|
||||
( cd "$ROOT_DIR" && debuild -S -i -I )
|
||||
|
||||
changes=( "$OUT_DIR"/fastfetch_*~${codename}_source.changes )
|
||||
if [[ ${#changes[@]} -ne 1 ]]; then
|
||||
echo "Unable to uniquely identify .changes for '$codename' in: $OUT_DIR" >&2
|
||||
printf 'Found:\n'; printf ' %s\n' "${changes[@]}" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo "[DRY-RUN] dput \"$PPA\" \"${changes[0]}\""
|
||||
else
|
||||
dput "$PPA" "${changes[0]}"
|
||||
fi
|
||||
|
||||
rm -f "$OUT_DIR"/fastfetch_*~${codename}_source.{changes,dsc,tar.*}
|
||||
|
||||
echo "<== Done: $codename"
|
||||
done
|
||||
|
||||
+1146
-194
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": [
|
||||
|
||||
+95
-21
@@ -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}'",
|
||||
"text": "clang --version | sed -n 's/.*version \\([0-9][0-9.]*\\).*/\\1/p'",
|
||||
"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,15 +250,28 @@
|
||||
},
|
||||
{
|
||||
"type": "users",
|
||||
"myselfOnly": true,
|
||||
"myselfOnly": true, // Only show current user
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}"
|
||||
},
|
||||
{
|
||||
"condition": { // Conditional module: only show on non-macOS
|
||||
"!system": "macOS"
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"folders": "/", // On macOS, "/System/Volumes/VM" works for me
|
||||
"folders": "/", // Check root filesystem
|
||||
"format": "{create-time:10} [{days} days]" // Show creation time and age in days
|
||||
},
|
||||
{
|
||||
"condition": { // Conditional module: only show on macOS
|
||||
"system": "macOS"
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"folders": "/System/Volumes/VM", // Work around for APFS on macOS
|
||||
"format": "{create-time:10} [{days} days]"
|
||||
},
|
||||
{
|
||||
@@ -230,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": "https://github.com/fastfetch-cli/fastfetch/raw/dev/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": "└────────────────────────────────────────┘"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": null,
|
||||
"display": {
|
||||
"key": {
|
||||
"type": "both",
|
||||
"paddingLeft": 6,
|
||||
"width": 17
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "|---------------------: {#1}Hardware{#} : ---------------------|"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"keyColor": "green",
|
||||
"type": "host"
|
||||
},
|
||||
{
|
||||
"keyColor": "green",
|
||||
"type": "cpu"
|
||||
},
|
||||
{
|
||||
"keyColor": "yellow",
|
||||
"type": "memory"
|
||||
},
|
||||
{
|
||||
"keyColor": "yellow",
|
||||
"type": "swap"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"keyIcon": "",
|
||||
"key": "Disks"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": " ",
|
||||
"format": " [{mountpoint}] - {size-used} / {size-total} ({size-percentage})"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "title",
|
||||
"format": "|-------------------------------------------------------|\u001b[40D: {#1}{user-name} @ {host-name}{#} :"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "os",
|
||||
"keyColor": "cyan"
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"keyColor": "cyan"
|
||||
},
|
||||
{
|
||||
"type": "packages",
|
||||
"keyColor": "red",
|
||||
"key": "Pkgs"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"keyColor": "red"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "Term",
|
||||
"keyColor": "red"
|
||||
},
|
||||
{
|
||||
"type": "locale",
|
||||
"keyColor": "magenta"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "|---------------------: {#1}Software{#} : ---------------------|"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "colors",
|
||||
"symbol": "circle",
|
||||
"paddingLeft": 8
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -8,8 +8,10 @@
|
||||
"width": 11
|
||||
},
|
||||
"bar": {
|
||||
"charElapsed": "=",
|
||||
"charTotal": "-",
|
||||
"char": {
|
||||
"elapsed": "=",
|
||||
"total": "-"
|
||||
},
|
||||
"width": 13
|
||||
},
|
||||
"percent": {
|
||||
|
||||
+13
-4
@@ -3,7 +3,12 @@
|
||||
"display": {
|
||||
"size": {
|
||||
"maxPrefix": "MB",
|
||||
"ndigits": 0
|
||||
"ndigits": 0,
|
||||
"spaceBeforeUnit": "never"
|
||||
},
|
||||
"freq": {
|
||||
"ndigits": 3,
|
||||
"spaceBeforeUnit": "never"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
@@ -16,7 +21,10 @@
|
||||
"format": "{release}"
|
||||
},
|
||||
"uptime",
|
||||
"packages",
|
||||
{
|
||||
"type": "packages",
|
||||
"combined": true
|
||||
},
|
||||
"shell",
|
||||
{
|
||||
"type": "display",
|
||||
@@ -36,11 +44,12 @@
|
||||
"cpu",
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "GPU"
|
||||
"key": "GPU",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"format": "{} / {}"
|
||||
"format": "{used} / {total}"
|
||||
},
|
||||
"break",
|
||||
"colors"
|
||||
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"home": "https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c",
|
||||
"license": "MIT compatible (embed in source)",
|
||||
"version": "2007-05-26 (Unicode 5.0)",
|
||||
"author": "Markus Kuhn",
|
||||
"modified": "CarterLi"
|
||||
}
|
||||
Vendored
-314
@@ -1,314 +0,0 @@
|
||||
/*
|
||||
* This is an implementation of wcwidth() and wcswidth() (defined in
|
||||
* IEEE Std 1002.1-2001) for Unicode.
|
||||
*
|
||||
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
|
||||
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
|
||||
*
|
||||
* In fixed-width output devices, Latin characters all occupy a single
|
||||
* "cell" position of equal width, whereas ideographic CJK characters
|
||||
* occupy two such cells. Interoperability between terminal-line
|
||||
* applications and (teletype-style) character terminals using the
|
||||
* UTF-8 encoding requires agreement on which character should advance
|
||||
* the cursor by how many cell positions. No established formal
|
||||
* standards exist at present on which Unicode character shall occupy
|
||||
* how many cell positions on character terminals. These routines are
|
||||
* a first attempt of defining such behavior based on simple rules
|
||||
* applied to data provided by the Unicode Consortium.
|
||||
*
|
||||
* For some graphical characters, the Unicode standard explicitly
|
||||
* defines a character-cell width via the definition of the East Asian
|
||||
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
|
||||
* In all these cases, there is no ambiguity about which width a
|
||||
* terminal shall use. For characters in the East Asian Ambiguous (A)
|
||||
* class, the width choice depends purely on a preference of backward
|
||||
* compatibility with either historic CJK or Western practice.
|
||||
* Choosing single-width for these characters is easy to justify as
|
||||
* the appropriate long-term solution, as the CJK practice of
|
||||
* displaying these characters as double-width comes from historic
|
||||
* implementation simplicity (8-bit encoded characters were displayed
|
||||
* single-width and 16-bit ones double-width, even for Greek,
|
||||
* Cyrillic, etc.) and not any typographic considerations.
|
||||
*
|
||||
* Much less clear is the choice of width for the Not East Asian
|
||||
* (Neutral) class. Existing practice does not dictate a width for any
|
||||
* of these characters. It would nevertheless make sense
|
||||
* typographically to allocate two character cells to characters such
|
||||
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
|
||||
* represented adequately with a single-width glyph. The following
|
||||
* routines at present merely assign a single-cell width to all
|
||||
* neutral characters, in the interest of simplicity. This is not
|
||||
* entirely satisfactory and should be reconsidered before
|
||||
* establishing a formal standard in this area. At the moment, the
|
||||
* decision which Not East Asian (Neutral) characters should be
|
||||
* represented by double-width glyphs cannot yet be answered by
|
||||
* applying a simple rule from the Unicode database content. Setting
|
||||
* up a proper standard for the behavior of UTF-8 character terminals
|
||||
* will require a careful analysis not only of each Unicode character,
|
||||
* but also of each presentation form, something the author of these
|
||||
* routines has avoided to do so far.
|
||||
*
|
||||
* http://www.unicode.org/unicode/reports/tr11/
|
||||
*
|
||||
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* for any purpose and without fee is hereby granted. The author
|
||||
* disclaims all warranties with regard to this software.
|
||||
*
|
||||
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||
*/
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
struct interval {
|
||||
int first;
|
||||
int last;
|
||||
};
|
||||
|
||||
/* auxiliary function for binary search in interval table */
|
||||
static int bisearch(wchar_t ucs, const struct interval *table, int max) {
|
||||
int min = 0;
|
||||
int mid;
|
||||
|
||||
if (ucs < table[0].first || ucs > table[max].last)
|
||||
return 0;
|
||||
while (max >= min) {
|
||||
mid = (min + max) / 2;
|
||||
if (ucs > table[mid].last)
|
||||
min = mid + 1;
|
||||
else if (ucs < table[mid].first)
|
||||
max = mid - 1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The following two functions define the column width of an ISO 10646
|
||||
* character as follows:
|
||||
*
|
||||
* - The null character (U+0000) has a column width of 0.
|
||||
*
|
||||
* - Other C0/C1 control characters and DEL will lead to a return
|
||||
* value of -1.
|
||||
*
|
||||
* - Non-spacing and enclosing combining characters (general
|
||||
* category code Mn or Me in the Unicode database) have a
|
||||
* column width of 0.
|
||||
*
|
||||
* - SOFT HYPHEN (U+00AD) has a column width of 1.
|
||||
*
|
||||
* - Other format characters (general category code Cf in the Unicode
|
||||
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
|
||||
*
|
||||
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
|
||||
* have a column width of 0.
|
||||
*
|
||||
* - Spacing characters in the East Asian Wide (W) or East Asian
|
||||
* Full-width (F) category as defined in Unicode Technical
|
||||
* Report #11 have a column width of 2.
|
||||
*
|
||||
* - All remaining characters (including all printable
|
||||
* ISO 8859-1 and WGL4 characters, Unicode control characters,
|
||||
* etc.) have a column width of 1.
|
||||
*
|
||||
* This implementation assumes that wchar_t characters are encoded
|
||||
* in ISO 10646.
|
||||
*/
|
||||
|
||||
int mk_wcwidth(wchar_t ucs)
|
||||
{
|
||||
/* sorted list of non-overlapping intervals of non-spacing characters */
|
||||
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
|
||||
static const struct interval combining[] = {
|
||||
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
|
||||
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
|
||||
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
|
||||
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
|
||||
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
|
||||
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
|
||||
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
|
||||
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
|
||||
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
|
||||
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
|
||||
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
|
||||
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
|
||||
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
|
||||
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
|
||||
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
|
||||
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
|
||||
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
|
||||
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
|
||||
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
|
||||
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
|
||||
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
|
||||
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
|
||||
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
|
||||
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
|
||||
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
|
||||
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
|
||||
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
|
||||
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
|
||||
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
|
||||
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
|
||||
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
|
||||
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
|
||||
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
|
||||
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
|
||||
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
|
||||
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
|
||||
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
|
||||
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
|
||||
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
|
||||
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
|
||||
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
|
||||
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
|
||||
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
|
||||
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
|
||||
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
|
||||
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
|
||||
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
|
||||
{ 0xE0100, 0xE01EF }
|
||||
};
|
||||
|
||||
/* test for 8-bit control characters */
|
||||
if (ucs == 0)
|
||||
return 0;
|
||||
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
|
||||
return -1;
|
||||
|
||||
/* binary search in table of non-spacing characters */
|
||||
if (bisearch(ucs, combining,
|
||||
sizeof(combining) / sizeof(struct interval) - 1))
|
||||
return 0;
|
||||
|
||||
/* if we arrive here, ucs is not a combining or C0/C1 control character */
|
||||
|
||||
return 1 +
|
||||
(ucs >= 0x1100 &&
|
||||
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
|
||||
ucs == 0x2329 || ucs == 0x232a ||
|
||||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
|
||||
ucs != 0x303f) || /* CJK ... Yi */
|
||||
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
|
||||
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
|
||||
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
|
||||
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
|
||||
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
|
||||
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
|
||||
|
||||
#ifndef _WIN32 // sizeof(wchar_t) == 2
|
||||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
|
||||
(ucs >= 0x30000 && ucs <= 0x3fffd) ||
|
||||
#endif
|
||||
0
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
int mk_wcswidth(const wchar_t *pwcs, size_t n)
|
||||
{
|
||||
int w, width = 0;
|
||||
|
||||
for (;*pwcs && n-- > 0; pwcs++)
|
||||
if ((w = mk_wcwidth(*pwcs)) < 0)
|
||||
return -1;
|
||||
else
|
||||
width += w;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The following functions are the same as mk_wcwidth() and
|
||||
* mk_wcswidth(), except that spacing characters in the East Asian
|
||||
* Ambiguous (A) category as defined in Unicode Technical Report #11
|
||||
* have a column width of 2. This variant might be useful for users of
|
||||
* CJK legacy encodings who want to migrate to UCS without changing
|
||||
* the traditional terminal character-width behaviour. It is not
|
||||
* otherwise recommended for general use.
|
||||
*/
|
||||
int mk_wcwidth_cjk(wchar_t ucs)
|
||||
{
|
||||
/* sorted list of non-overlapping intervals of East Asian Ambiguous
|
||||
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
|
||||
static const struct interval ambiguous[] = {
|
||||
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
|
||||
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
|
||||
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
|
||||
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
|
||||
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
|
||||
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
|
||||
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
|
||||
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
|
||||
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
|
||||
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
|
||||
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
|
||||
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
|
||||
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
|
||||
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
|
||||
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
|
||||
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
|
||||
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
|
||||
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
|
||||
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
|
||||
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
|
||||
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
|
||||
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
|
||||
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
|
||||
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
|
||||
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
|
||||
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
|
||||
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
|
||||
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
|
||||
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
|
||||
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
|
||||
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
|
||||
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
|
||||
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
|
||||
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
|
||||
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
|
||||
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
|
||||
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
|
||||
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
|
||||
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
|
||||
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
|
||||
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
|
||||
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
|
||||
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
|
||||
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
|
||||
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
|
||||
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
|
||||
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
|
||||
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
|
||||
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
|
||||
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
|
||||
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
|
||||
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
|
||||
};
|
||||
|
||||
/* binary search in table of non-spacing characters */
|
||||
if (bisearch(ucs, ambiguous,
|
||||
sizeof(ambiguous) / sizeof(struct interval) - 1))
|
||||
return 2;
|
||||
|
||||
return mk_wcwidth(ucs);
|
||||
}
|
||||
|
||||
|
||||
int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
|
||||
{
|
||||
int w, width = 0;
|
||||
|
||||
for (;*pwcs && n-- > 0; pwcs++)
|
||||
if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
|
||||
return -1;
|
||||
else
|
||||
width += w;
|
||||
|
||||
return width;
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/ridiculousfish/widecharwidth",
|
||||
"license": "Public domain",
|
||||
"version": "Unicode 17",
|
||||
"author": "ridiculousfish"
|
||||
}
|
||||
+1590
File diff suppressed because it is too large
Load Diff
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__)
|
||||
|
||||
+97
-31
@@ -13,74 +13,137 @@
|
||||
bool ffParseModuleOptions(const char* key, const char* value)
|
||||
{
|
||||
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
|
||||
|
||||
if (value && !*value) value = NULL;
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (baseInfo->parseCommandOptions(baseInfo, key, value)) return true;
|
||||
const char* subKey = ffOptionTestPrefix(key, baseInfo->name);
|
||||
if (subKey != NULL)
|
||||
{
|
||||
if (subKey[0] == '\0' || subKey[0] == '-') // Key is exactly the module name or has a leading '-'
|
||||
{
|
||||
fprintf(stderr, "Error: unknown module key %s\n", key);
|
||||
exit(477);
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY moduleName = ffStrbufCreateS(baseInfo->name);
|
||||
ffStrbufLowerCase(&moduleName);
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY jsonKey = ffStrbufCreate();
|
||||
bool flag = false;
|
||||
for (const char* p = subKey; *p; ++p)
|
||||
{
|
||||
if (*p == '-')
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
fprintf(stderr, "Error: invalid double `-` in module key %s\n", key);
|
||||
exit(477);
|
||||
}
|
||||
flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isalpha((unsigned char)*p) && !isdigit((unsigned char)*p))
|
||||
{
|
||||
fprintf(stderr, "Error: invalid character `%c` in module key %s\n", *p, key);
|
||||
exit(477);
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
flag = false;
|
||||
ffStrbufAppendC(&jsonKey, (char) toupper((unsigned char) *p));
|
||||
}
|
||||
else
|
||||
ffStrbufAppendC(&jsonKey, *p);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Error: Unsupported module option: %s\n", key);
|
||||
fputs(" Support of module options has been removed. Please add the flag to the JSON config instead.\n", stderr);
|
||||
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ? value : "true", value ? "\"" : "");
|
||||
fputs(" See <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration> for more information.\n", stderr);
|
||||
exit(477);
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME))
|
||||
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME, ':'))
|
||||
ffPrepareCPUUsage();
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME))
|
||||
ffPrepareDiskIO(&options->diskIo);
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME))
|
||||
ffPrepareNetIO(&options->netIo);
|
||||
|
||||
if(instance.config.general.multithreading)
|
||||
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME, ':'))
|
||||
{
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
|
||||
ffPreparePublicIp(&options->publicIP);
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
|
||||
ffPrepareWeather(&options->weather);
|
||||
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME, ':'))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
|
||||
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME, ':'))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
|
||||
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME, ':'))
|
||||
{
|
||||
__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 +154,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,7 @@ 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);
|
||||
bool ffParseModuleOptions(const char* key, const char* value);
|
||||
|
||||
+56
-3
@@ -162,14 +162,67 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result)
|
||||
return ffDBusGetUint(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg)
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result)
|
||||
{
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_INT16)
|
||||
{
|
||||
int16_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_INT32)
|
||||
{
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_BYTE)
|
||||
{
|
||||
uint8_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_UINT16)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = (int16_t) value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_UINT32)
|
||||
{
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT)
|
||||
return false;
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
return ffDBusGetInt(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2)
|
||||
{
|
||||
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
|
||||
if(message == NULL)
|
||||
return NULL;
|
||||
|
||||
if (arg)
|
||||
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
|
||||
if (arg1)
|
||||
{
|
||||
if (arg2)
|
||||
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID);
|
||||
else
|
||||
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL);
|
||||
|
||||
|
||||
+3
-2
@@ -31,14 +31,15 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); //Returns an
|
||||
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result);
|
||||
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result);
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg);
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2);
|
||||
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property);
|
||||
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
|
||||
|
||||
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface)
|
||||
{
|
||||
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface);
|
||||
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, NULL);
|
||||
}
|
||||
|
||||
#endif // FF_HAVE_DBUS
|
||||
|
||||
@@ -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, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
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, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
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, true);
|
||||
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);
|
||||
+12
-14
@@ -25,10 +25,12 @@ static void initState(FFstate* state)
|
||||
state->logoHeight = 0;
|
||||
state->keysHeight = 0;
|
||||
state->terminalLightTheme = false;
|
||||
state->titleFqdn = false;
|
||||
|
||||
ffPlatformInit(&state->platform);
|
||||
state->configDoc = NULL;
|
||||
state->resultDoc = NULL;
|
||||
state->dynamicInterval = 0;
|
||||
|
||||
{
|
||||
// don't enable bright color if the terminal is in light mode
|
||||
@@ -42,14 +44,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, "")`
|
||||
@@ -74,6 +75,9 @@ static void resetConsole(void)
|
||||
#if defined(_WIN32)
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
if(instance.state.dynamicInterval > 0)
|
||||
fputs("\033[?1049l", stdout); // Disable alternate buffer
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -96,11 +100,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;
|
||||
|
||||
@@ -135,14 +134,17 @@ void ffStart(void)
|
||||
if(ffDisableLinewrap)
|
||||
fputs("\033[?7l", stdout);
|
||||
|
||||
if(instance.state.dynamicInterval > 0)
|
||||
{
|
||||
fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
ffLogoPrint();
|
||||
}
|
||||
|
||||
void ffFinish(void)
|
||||
{
|
||||
if(instance.config.logo.printRemaining)
|
||||
ffLogoPrintRemaining();
|
||||
|
||||
resetConsole();
|
||||
}
|
||||
|
||||
@@ -150,7 +152,6 @@ static void destroyConfig(void)
|
||||
{
|
||||
ffOptionsDestroyLogo(&instance.config.logo);
|
||||
ffOptionsDestroyGeneral(&instance.config.general);
|
||||
ffOptionsDestroyModules(&instance.config.modules);
|
||||
ffOptionsDestroyDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
@@ -214,9 +215,6 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_ZLIB
|
||||
"zlib\n"
|
||||
#endif
|
||||
#if FF_HAVE_XFCONF
|
||||
"xfconf\n"
|
||||
#endif
|
||||
#if FF_HAVE_SQLITE3
|
||||
"sqlite3\n"
|
||||
#endif
|
||||
|
||||
+22
-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
|
||||
@@ -222,6 +240,9 @@ static inline bool ffSearchUserConfigFile(const FFlist* configDirs, const char*
|
||||
return false;
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void);
|
||||
bool ffRemoveFile(const char* fileName);
|
||||
|
||||
#ifdef _WIN32
|
||||
// Only O_RDONLY is supported
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, bool directory);
|
||||
|
||||
+29
-11
@@ -15,11 +15,8 @@
|
||||
|
||||
#if FF_HAVE_WORDEXP
|
||||
#include <wordexp.h>
|
||||
#elif FF_HAVE_GLOB
|
||||
#warning "<wordexp.h> is not available, use <glob.h> instead"
|
||||
#include <glob.h>
|
||||
#else
|
||||
#warning "Neither <wordexp.h> nor <glob.h> is available"
|
||||
#include <glob.h>
|
||||
#endif
|
||||
|
||||
static void createSubfolders(const char* fileName)
|
||||
@@ -136,14 +133,14 @@ bool ffAppendFileBufferRelative(int dfd, const char* fileName, FFstrbuf* buffer)
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* out)
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
#if FF_HAVE_WORDEXP // https://github.com/termux/termux-packages/pull/7056
|
||||
#if FF_HAVE_WORDEXP
|
||||
|
||||
wordexp_t exp;
|
||||
if (wordexp(in, &exp, 0) != 0)
|
||||
if (wordexp(in, &exp, 0) != 0) // WARN: 0 = no safety flags; command substitution allowed
|
||||
return false;
|
||||
|
||||
if (exp.we_wordc >= 1)
|
||||
@@ -154,16 +151,23 @@ bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* o
|
||||
|
||||
wordfree(&exp);
|
||||
|
||||
#elif FF_HAVE_GLOB
|
||||
#else
|
||||
|
||||
glob_t gb;
|
||||
if (glob(in, GLOB_NOSORT | GLOB_TILDE, NULL, &gb) != 0)
|
||||
if (glob(in, GLOB_NOSORT
|
||||
#ifdef GLOB_TILDE
|
||||
| GLOB_TILDE
|
||||
#endif
|
||||
#ifdef GLOB_BRACE
|
||||
| GLOB_BRACE
|
||||
#endif
|
||||
, NULL, &gb) != 0)
|
||||
return false;
|
||||
|
||||
if (gb.gl_matchc >= 1)
|
||||
if (gb.gl_pathc >= 1)
|
||||
{
|
||||
result = true;
|
||||
ffStrbufSetS(out, gb.gl_pathv[gb.gl_matchc > 1 ? ffTimeGetNow() % gb.gl_matchc : 0]);
|
||||
ffStrbufSetS(out, gb.gl_pathv[gb.gl_pathc > 1 ? ffTimeGetNow() % (unsigned) gb.gl_pathc : 0]);
|
||||
}
|
||||
|
||||
globfree(&gb);
|
||||
@@ -358,3 +362,17 @@ void ffListFilesRecursively(const char* path, bool pretty)
|
||||
ffStrbufEnsureEndsWithC(&folder, '/');
|
||||
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void)
|
||||
{
|
||||
static FFNativeFD hNullFile = -1;
|
||||
if (hNullFile != -1)
|
||||
return hNullFile;
|
||||
hNullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
return hNullFile;
|
||||
}
|
||||
|
||||
bool ffRemoveFile(const char* fileName)
|
||||
{
|
||||
return unlink(fileName) == 0;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ bool ffSuppressIO(bool suppress)
|
||||
static bool init = false;
|
||||
static HANDLE hOrigOut = INVALID_HANDLE_VALUE;
|
||||
static HANDLE hOrigErr = INVALID_HANDLE_VALUE;
|
||||
static HANDLE hNullFile = INVALID_HANDLE_VALUE;
|
||||
HANDLE hNullFile = ffGetNullFD();
|
||||
static int fOrigOut = -1;
|
||||
static int fOrigErr = -1;
|
||||
static int fNullFile = -1;
|
||||
@@ -187,7 +187,6 @@ bool ffSuppressIO(bool suppress)
|
||||
|
||||
hOrigOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
hOrigErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
hNullFile = CreateFileW(L"NUL", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
|
||||
fOrigOut = _dup(STDOUT_FILENO);
|
||||
fOrigErr = _dup(STDERR_FILENO);
|
||||
fNullFile = _open_osfhandle((intptr_t) hNullFile, 0);
|
||||
@@ -352,3 +351,28 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void)
|
||||
{
|
||||
static FFNativeFD hNullFile = INVALID_HANDLE_VALUE;
|
||||
if (hNullFile != INVALID_HANDLE_VALUE)
|
||||
return hNullFile;
|
||||
hNullFile = CreateFileW(
|
||||
L"NUL",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
&(SECURITY_ATTRIBUTES){
|
||||
.nLength = sizeof(SECURITY_ATTRIBUTES),
|
||||
.lpSecurityDescriptor = NULL,
|
||||
.bInheritHandle = TRUE,
|
||||
});
|
||||
return hNullFile;
|
||||
}
|
||||
|
||||
bool ffRemoveFile(const char* fileName)
|
||||
{
|
||||
return DeleteFileA(fileName) != FALSE;
|
||||
}
|
||||
|
||||
+135
-42
@@ -4,6 +4,7 @@
|
||||
#include "common/printing.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/time.h"
|
||||
#include "detection/version/version.h"
|
||||
#include "modules/modules.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
@@ -11,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);
|
||||
}
|
||||
|
||||
@@ -95,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;
|
||||
@@ -114,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': {
|
||||
@@ -135,41 +158,78 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
ffPrepareCPUUsage();
|
||||
break;
|
||||
}
|
||||
case 'c': case 'C': {
|
||||
if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyCommandOptions))) FFCommandOptions options;
|
||||
ffInitCommandOptions(&options);
|
||||
if (module) ffCommandModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareCommand(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'd': case 'D': {
|
||||
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME))
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool matchesJsonArray(const char* str, yyjson_val* val)
|
||||
{
|
||||
assert(val);
|
||||
|
||||
if (unsafe_yyjson_is_str(val))
|
||||
return ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(val));
|
||||
|
||||
if (!unsafe_yyjson_is_arr(val)) return false;
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_val* item;
|
||||
yyjson_arr_foreach(val, idx, max, item)
|
||||
{
|
||||
if (yyjson_is_str(item) && ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(item)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
{
|
||||
yyjson_val* const root = yyjson_doc_get_root(instance.state.configDoc);
|
||||
@@ -182,6 +242,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;
|
||||
@@ -197,6 +258,38 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
module = NULL;
|
||||
else if (yyjson_is_obj(module))
|
||||
{
|
||||
yyjson_val* conditions = yyjson_obj_get(module, "condition");
|
||||
if (conditions)
|
||||
{
|
||||
if (!yyjson_is_obj(conditions))
|
||||
return "Property 'conditions' must be an object";
|
||||
|
||||
yyjson_val* system = yyjson_obj_get(conditions, "system");
|
||||
if (system && !matchesJsonArray(ffVersionResult.sysName, system))
|
||||
continue;
|
||||
|
||||
system = yyjson_obj_get(conditions, "!system");
|
||||
if (system && matchesJsonArray(ffVersionResult.sysName, system))
|
||||
continue;
|
||||
|
||||
yyjson_val* arch = yyjson_obj_get(conditions, "arch");
|
||||
if (arch && !matchesJsonArray(ffVersionResult.architecture, arch))
|
||||
continue;
|
||||
|
||||
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"));
|
||||
if (!type) return "module object must contain a \"type\" key ( case sensitive )";
|
||||
if (yyjson_obj_size(module) == 1) // contains only Property type
|
||||
@@ -207,8 +300,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;
|
||||
FF_MAYBE_UNUSED 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;
|
||||
FF_MAYBE_UNUSED 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] == '[')
|
||||
{
|
||||
|
||||
+14
-5
@@ -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;
|
||||
@@ -42,7 +44,13 @@ typedef enum __attribute__((__packed__)) FFModuleKeyType
|
||||
FF_MODULE_KEY_TYPE_NONE = 0,
|
||||
FF_MODULE_KEY_TYPE_STRING = 1 << 0,
|
||||
FF_MODULE_KEY_TYPE_ICON = 1 << 1,
|
||||
FF_MODULE_KEY_TYPE_BOTH = FF_MODULE_KEY_TYPE_STRING | FF_MODULE_KEY_TYPE_ICON,
|
||||
FF_MODULE_KEY_TYPE_SPACE_SHIFT = 4,
|
||||
FF_MODULE_KEY_TYPE_BOTH_0 = FF_MODULE_KEY_TYPE_STRING | FF_MODULE_KEY_TYPE_ICON,
|
||||
FF_MODULE_KEY_TYPE_BOTH_1 = FF_MODULE_KEY_TYPE_BOTH_0 | (1 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
|
||||
FF_MODULE_KEY_TYPE_BOTH = FF_MODULE_KEY_TYPE_BOTH_1, // alias
|
||||
FF_MODULE_KEY_TYPE_BOTH_2 = FF_MODULE_KEY_TYPE_BOTH_0 | (2 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
|
||||
FF_MODULE_KEY_TYPE_BOTH_3 = FF_MODULE_KEY_TYPE_BOTH_0 | (3 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
|
||||
FF_MODULE_KEY_TYPE_BOTH_4 = FF_MODULE_KEY_TYPE_BOTH_0 | (4 << FF_MODULE_KEY_TYPE_SPACE_SHIFT),
|
||||
FF_MODULE_KEY_TYPE_FORCE_UNSIGNED = UINT8_MAX,
|
||||
} FFModuleKeyType;
|
||||
|
||||
@@ -63,7 +71,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 +101,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);
|
||||
|
||||
@@ -28,17 +28,12 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
ffPrintColor(&instance.config.display.colorKeys);
|
||||
}
|
||||
|
||||
bool hasIcon = false;
|
||||
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_ICON && moduleArgs && moduleArgs->keyIcon.length > 0)
|
||||
{
|
||||
ffStrbufWriteTo(&moduleArgs->keyIcon, stdout);
|
||||
hasIcon = true;
|
||||
}
|
||||
|
||||
if (instance.config.display.keyType & FF_MODULE_KEY_TYPE_STRING)
|
||||
{
|
||||
if(hasIcon)
|
||||
putchar(' ');
|
||||
ffPrintCharTimes(' ', instance.config.display.keyType >> FF_MODULE_KEY_TYPE_SPACE_SHIFT);
|
||||
|
||||
//NULL check is required for modules with custom keys, e.g. disk with the folder path
|
||||
if((printType & FF_PRINT_TYPE_NO_CUSTOM_KEY) || !moduleArgs || moduleArgs->key.length == 0)
|
||||
@@ -136,6 +131,12 @@ void ffPrintCharTimes(char c, uint32_t times)
|
||||
if(times == 0)
|
||||
return;
|
||||
|
||||
if(times == 1)
|
||||
{
|
||||
putchar(c);
|
||||
return;
|
||||
}
|
||||
|
||||
char str[32];
|
||||
memset(str, c, sizeof(str)); //2 instructions when compiling with AVX2 enabled
|
||||
for(uint32_t i = sizeof(str); i <= times; i += (uint32_t)sizeof(str))
|
||||
|
||||
+25
-4
@@ -2,13 +2,30 @@
|
||||
|
||||
#include "util/FFstrbuf.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifndef _WIN32
|
||||
#include <sys/types.h> // pid_t
|
||||
#endif
|
||||
|
||||
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr);
|
||||
typedef struct FFProcessHandle {
|
||||
#if _WIN32
|
||||
void* pid; // HANDLE
|
||||
void* pipeRead; // HANDLE
|
||||
#else
|
||||
pid_t pid;
|
||||
int pipeRead;
|
||||
#endif
|
||||
} FFProcessHandle;
|
||||
|
||||
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle);
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer); // Destroys handle internally
|
||||
|
||||
static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[])
|
||||
{
|
||||
const char* error = ffProcessAppendOutput(buffer, argv, false);
|
||||
FFProcessHandle handle;
|
||||
const char* error = ffProcessSpawn(argv, false, &handle);
|
||||
if (error) return error;
|
||||
|
||||
error = ffProcessReadOutput(&handle, buffer);
|
||||
if (!error)
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
return error;
|
||||
@@ -16,7 +33,11 @@ static inline const char* ffProcessAppendStdOut(FFstrbuf* buffer, char* const ar
|
||||
|
||||
static inline const char* ffProcessAppendStdErr(FFstrbuf* buffer, char* const argv[])
|
||||
{
|
||||
const char* error = ffProcessAppendOutput(buffer, argv, true);
|
||||
FFProcessHandle handle;
|
||||
const char* error = ffProcessSpawn(argv, true, &handle);
|
||||
if (error) return error;
|
||||
|
||||
error = ffProcessReadOutput(&handle, buffer);
|
||||
if (!error)
|
||||
ffStrbufTrimRightSpace(buffer);
|
||||
return error;
|
||||
|
||||
+128
-31
@@ -11,7 +11,10 @@
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <spawn.h>
|
||||
|
||||
#if !(__ANDROID__ || __OpenBSD__)
|
||||
#include <spawn.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
@@ -55,19 +58,27 @@ static inline int ffPipe2(int* fds, int flags)
|
||||
|
||||
|
||||
// Not thread-safe
|
||||
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
|
||||
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle)
|
||||
{
|
||||
int pipes[2];
|
||||
const int timeout = instance.config.general.processingTimeout;
|
||||
|
||||
if(ffPipe2(pipes, O_CLOEXEC) == -1)
|
||||
return "pipe() failed";
|
||||
|
||||
pid_t childPid = -1;
|
||||
int nullFile = ffGetNullFD();
|
||||
|
||||
#if !(__ANDROID__ || __OpenBSD__)
|
||||
|
||||
// NetBSD / Darwin: native syscall
|
||||
// Linux (glibc): clone3-execve
|
||||
// FreeBSD: vfork-execve
|
||||
// illumos: vforkx-execve
|
||||
// OpenBSD / Android (bionic): fork-execve
|
||||
|
||||
posix_spawn_file_actions_t file_actions;
|
||||
posix_spawn_file_actions_init(&file_actions);
|
||||
posix_spawn_file_actions_adddup2(&file_actions, pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
|
||||
posix_spawn_file_actions_addopen(&file_actions, useStdErr ? STDOUT_FILENO : STDERR_FILENO, "/dev/null", O_WRONLY, 0);
|
||||
pid_t childPid = -1;
|
||||
posix_spawn_file_actions_adddup2(&file_actions, nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
|
||||
|
||||
static char* oldLang = NULL;
|
||||
static int langIndex = -1;
|
||||
@@ -113,17 +124,55 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
|
||||
posix_spawn_file_actions_destroy(&file_actions);
|
||||
|
||||
close(pipes[1]);
|
||||
if (ret != 0)
|
||||
{
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
return "posix_spawnp() failed";
|
||||
}
|
||||
|
||||
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
|
||||
#else
|
||||
|
||||
// https://github.com/termux/termux-packages/issues/25369
|
||||
childPid = fork();
|
||||
if(childPid == -1)
|
||||
{
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
return "fork() failed";
|
||||
}
|
||||
|
||||
if(childPid == 0)
|
||||
{
|
||||
// Child process
|
||||
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
|
||||
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
|
||||
putenv("LANG=C.UTF-8");
|
||||
execvp(argv[0], argv);
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
close(pipes[1]);
|
||||
outHandle->pid = childPid;
|
||||
outHandle->pipeRead = pipes[0];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
{
|
||||
assert(handle->pipeRead != -1);
|
||||
assert(handle->pid != -1);
|
||||
|
||||
const int32_t timeout = instance.config.general.processingTimeout;
|
||||
FF_AUTO_CLOSE_FD int childPipeFd = handle->pipeRead;
|
||||
pid_t childPid = handle->pid;
|
||||
handle->pipeRead = -1;
|
||||
handle->pid = -1;
|
||||
char str[FF_PIPE_BUFSIZ];
|
||||
|
||||
while(1)
|
||||
for (;;)
|
||||
{
|
||||
if (timeout >= 0)
|
||||
{
|
||||
@@ -151,14 +200,14 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
{
|
||||
kill(childPid, SIGTERM);
|
||||
waitpid(childPid, NULL, 0);
|
||||
return "poll(&pollfd, 1, timeout) error";
|
||||
return "poll(&pollfd, 1, timeout) error: not EINTR";
|
||||
}
|
||||
}
|
||||
else if (pollfd.revents & POLLERR)
|
||||
{
|
||||
kill(childPid, SIGTERM);
|
||||
waitpid(childPid, NULL, 0);
|
||||
return "poll(&pollfd, 1, timeout) error";
|
||||
return "poll(&pollfd, 1, timeout) error: POLLERR";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,7 +222,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
if (!WIFEXITED(stat_loc))
|
||||
return "child process exited abnormally";
|
||||
if (WEXITSTATUS(stat_loc) == 127)
|
||||
return "command was not found";
|
||||
return "command not found";
|
||||
// We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c`
|
||||
return NULL;
|
||||
}
|
||||
@@ -186,7 +235,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
else
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed";
|
||||
}
|
||||
@@ -196,15 +245,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
|
||||
}
|
||||
|
||||
@@ -398,33 +474,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);
|
||||
@@ -433,6 +529,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__)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "common/processing.h"
|
||||
#include "common/io/io.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
#include <ntstatus.h>
|
||||
#include <winternl.h>
|
||||
|
||||
@@ -45,12 +45,13 @@ static void argvToCmdline(char* const argv[], FFstrbuf* result)
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
|
||||
const char* ffProcessSpawn(char* const argv[], bool useStdErr, FFProcessHandle* outHandle)
|
||||
{
|
||||
int timeout = instance.config.general.processingTimeout;
|
||||
const int32_t timeout = instance.config.general.processingTimeout;
|
||||
|
||||
wchar_t pipeName[32];
|
||||
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u", GetCurrentProcessId());
|
||||
static unsigned pidCounter = 0;
|
||||
swprintf(pipeName, ARRAY_SIZE(pipeName), L"\\\\.\\pipe\\FASTFETCH-%u-%u", GetCurrentProcessId(), ++pidCounter);
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = CreateNamedPipeW(
|
||||
pipeName,
|
||||
@@ -81,47 +82,68 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
if (hChildPipeWrite == INVALID_HANDLE_VALUE)
|
||||
return "CreateFileW(L\"\\\\.\\pipe\\FASTFETCH-$(PID)\") failed";
|
||||
|
||||
PROCESS_INFORMATION piProcInfo = {0};
|
||||
|
||||
BOOL success;
|
||||
|
||||
PROCESS_INFORMATION piProcInfo = {};
|
||||
STARTUPINFOA siStartInfo = {
|
||||
.cb = sizeof(siStartInfo),
|
||||
.dwFlags = STARTF_USESTDHANDLES,
|
||||
};
|
||||
if (useStdErr)
|
||||
{
|
||||
STARTUPINFOA siStartInfo = {
|
||||
.cb = sizeof(siStartInfo),
|
||||
.dwFlags = STARTF_USESTDHANDLES,
|
||||
};
|
||||
if (useStdErr)
|
||||
siStartInfo.hStdError = hChildPipeWrite;
|
||||
else
|
||||
siStartInfo.hStdOutput = hChildPipeWrite;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
|
||||
argvToCmdline(argv, &cmdline);
|
||||
|
||||
success = CreateProcessA(
|
||||
NULL, // application name
|
||||
cmdline.chars, // command line
|
||||
NULL, // process security attributes
|
||||
NULL, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
0, // creation flags
|
||||
NULL, // use parent's environment
|
||||
NULL, // use parent's current directory
|
||||
&siStartInfo, // STARTUPINFO pointer
|
||||
&piProcInfo // receives PROCESS_INFORMATION
|
||||
);
|
||||
siStartInfo.hStdOutput = ffGetNullFD();
|
||||
siStartInfo.hStdError = hChildPipeWrite;
|
||||
}
|
||||
else
|
||||
{
|
||||
siStartInfo.hStdOutput = hChildPipeWrite;
|
||||
siStartInfo.hStdError = ffGetNullFD();
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY cmdline = ffStrbufCreate();
|
||||
argvToCmdline(argv, &cmdline);
|
||||
|
||||
BOOL success = CreateProcessA(
|
||||
NULL, // application name
|
||||
cmdline.chars, // command line
|
||||
NULL, // process security attributes
|
||||
NULL, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
0, // creation flags
|
||||
NULL, // use parent's environment
|
||||
NULL, // use parent's current directory
|
||||
&siStartInfo, // STARTUPINFO pointer
|
||||
&piProcInfo // receives PROCESS_INFORMATION
|
||||
);
|
||||
|
||||
CloseHandle(hChildPipeWrite);
|
||||
if(!success)
|
||||
{
|
||||
if (GetLastError() == ERROR_FILE_NOT_FOUND)
|
||||
return "command not found";
|
||||
return "CreateProcessA() failed";
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hProcess = piProcInfo.hProcess;
|
||||
FF_MAYBE_UNUSED FF_AUTO_CLOSE_FD HANDLE hThread = piProcInfo.hThread;
|
||||
CloseHandle(piProcInfo.hThread); // we don't need the thread handle
|
||||
outHandle->pid = piProcInfo.hProcess;
|
||||
outHandle->pipeRead = hChildPipeRead;
|
||||
hChildPipeRead = INVALID_HANDLE_VALUE; // ownership transferred, don't close it
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffProcessReadOutput(FFProcessHandle* handle, FFstrbuf* buffer)
|
||||
{
|
||||
assert(handle->pipeRead != INVALID_HANDLE_VALUE);
|
||||
assert(handle->pid != INVALID_HANDLE_VALUE);
|
||||
|
||||
int32_t timeout = instance.config.general.processingTimeout;
|
||||
FF_AUTO_CLOSE_FD HANDLE hProcess = handle->pid;
|
||||
FF_AUTO_CLOSE_FD HANDLE hChildPipeRead = handle->pipeRead;
|
||||
handle->pid = INVALID_HANDLE_VALUE;
|
||||
handle->pipeRead = INVALID_HANDLE_VALUE;
|
||||
|
||||
char str[FF_PIPE_BUFSIZ];
|
||||
DWORD nRead = 0;
|
||||
OVERLAPPED overlapped = { };
|
||||
OVERLAPPED overlapped = {};
|
||||
// ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED
|
||||
do
|
||||
{
|
||||
@@ -158,7 +180,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
break;
|
||||
|
||||
case ERROR_BROKEN_PIPE:
|
||||
return NULL;
|
||||
goto exit;
|
||||
|
||||
default:
|
||||
CancelIo(hChildPipeRead);
|
||||
@@ -169,6 +191,13 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
ffStrbufAppendNS(buffer, nRead, str);
|
||||
} while (nRead > 0);
|
||||
|
||||
exit:
|
||||
{
|
||||
DWORD exitCode = 0;
|
||||
if (GetExitCodeProcess(hProcess, &exitCode) && exitCode != STILL_ACTIVE && exitCode != 0)
|
||||
return "Child process exited with an error";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
+126
-52
@@ -184,7 +184,7 @@ FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type)
|
||||
}
|
||||
#endif //FF_HAVE_DCONF
|
||||
|
||||
FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type)
|
||||
FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type)
|
||||
{
|
||||
FFvariant gsettings = ffSettingsGetGSettings(gsettingsSchemaName, gsettingsPath, gsettingsKey, type);
|
||||
|
||||
@@ -196,77 +196,151 @@ FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, c
|
||||
return ffSettingsGetDConf(dconfKey, type);
|
||||
}
|
||||
|
||||
#ifdef FF_HAVE_XFCONF
|
||||
#include <xfconf/xfconf.h>
|
||||
|
||||
typedef struct XFConfData
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(xfconf_channel_get)
|
||||
FF_LIBRARY_SYMBOL(xfconf_channel_has_property)
|
||||
FF_LIBRARY_SYMBOL(xfconf_channel_get_string)
|
||||
FF_LIBRARY_SYMBOL(xfconf_channel_get_bool)
|
||||
FF_LIBRARY_SYMBOL(xfconf_channel_get_int)
|
||||
FF_LIBRARY_SYMBOL(xfconf_init)
|
||||
|
||||
bool inited;
|
||||
} XFConfData;
|
||||
|
||||
static const XFConfData* getXFConfData(void)
|
||||
{
|
||||
static XFConfData data;
|
||||
|
||||
if (!data.inited)
|
||||
{
|
||||
data.inited = true;
|
||||
FF_LIBRARY_LOAD(libxfconf, NULL, "libxfconf-0" FF_LIBRARY_EXTENSION, 4);
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get, NULL)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_has_property, NULL)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_string, NULL)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_bool, NULL)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_int, NULL)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_init, NULL)
|
||||
if(!data.ffxfconf_init(NULL))
|
||||
data.ffxfconf_init = NULL;
|
||||
else
|
||||
libxfconf = NULL;
|
||||
}
|
||||
|
||||
if(!data.ffxfconf_init)
|
||||
return NULL;
|
||||
|
||||
return &data;
|
||||
}
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
|
||||
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
|
||||
{
|
||||
const XFConfData* data = getXFConfData();
|
||||
if(data == NULL)
|
||||
FFDBusData dbus;
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
|
||||
return FF_VARIANT_NULL;
|
||||
|
||||
XfconfChannel* channel = data->ffxfconf_channel_get(channelName); // Never fails according to documentation but rather returns an empty channel
|
||||
|
||||
if(!data->ffxfconf_channel_has_property(channel, propertyName))
|
||||
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetProperty", channelName, propertyName);
|
||||
if(!reply)
|
||||
return FF_VARIANT_NULL;
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_INT)
|
||||
return (FFvariant) {.intValue = data->ffxfconf_channel_get_int(channel, propertyName, 0)};
|
||||
{
|
||||
int32_t value;
|
||||
if (ffDBusGetInt(&dbus, &rootIterator, &value))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .intValue = value };
|
||||
}
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_STRING)
|
||||
return (FFvariant) {.strValue = data->ffxfconf_channel_get_string(channel, propertyName, NULL)};
|
||||
{
|
||||
FFstrbuf value = ffStrbufCreate();
|
||||
if (ffDBusGetString(&dbus, &rootIterator, &value))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
|
||||
}
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_BOOL)
|
||||
return (FFvariant) {.boolValue = data->ffxfconf_channel_get_bool(channel, propertyName, false), .boolValueSet = true};
|
||||
{
|
||||
bool value;
|
||||
if (ffDBusGetBool(&dbus, &rootIterator, &value))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .boolValue = value, .boolValueSet = true };
|
||||
}
|
||||
}
|
||||
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#else //FF_HAVE_XFCONF
|
||||
|
||||
#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \
|
||||
{ \
|
||||
if(!(dbus).lib->ffdbus_message_iter_next(iterator)) \
|
||||
break; \
|
||||
continue; \
|
||||
}
|
||||
|
||||
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
|
||||
{
|
||||
FFDBusData dbus;
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL)
|
||||
return FF_VARIANT_NULL;
|
||||
|
||||
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetAllProperties", channelName, propertyPrefix);
|
||||
if(!reply)
|
||||
return FF_VARIANT_NULL;
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
DBusMessageIter arrayIterator;
|
||||
dbus.lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if(dbus.lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY)
|
||||
FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
|
||||
|
||||
DBusMessageIter dictIterator;
|
||||
dbus.lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator);
|
||||
|
||||
const char* key;
|
||||
dbus.lib->ffdbus_message_iter_get_basic(&dictIterator, &key);
|
||||
|
||||
if (cb(data, key)) FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator)
|
||||
dbus.lib->ffdbus_message_iter_next(&dictIterator);
|
||||
|
||||
if(type == FF_VARIANT_TYPE_INT)
|
||||
{
|
||||
int32_t value;
|
||||
if (ffDBusGetInt(&dbus, &dictIterator, &value))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .intValue = value };
|
||||
}
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_STRING)
|
||||
{
|
||||
FFstrbuf value = ffStrbufCreate();
|
||||
if (ffDBusGetString(&dbus, &dictIterator, &value))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
|
||||
}
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
if(type == FF_VARIANT_TYPE_BOOL)
|
||||
{
|
||||
bool value;
|
||||
if (ffDBusGetBool(&dbus, &dictIterator, &value))
|
||||
{
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .boolValue = value, .boolValueSet = true };
|
||||
}
|
||||
}
|
||||
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#else //FF_HAVE_DBUS
|
||||
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type)
|
||||
{
|
||||
FF_UNUSED(channelName, propertyName, type)
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#endif //FF_HAVE_XFCONF
|
||||
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb)
|
||||
{
|
||||
FF_UNUSED(channelName, propertyPrefix, type, data, cb);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#endif //FF_HAVE_DBUS
|
||||
|
||||
#ifdef FF_HAVE_SQLITE3
|
||||
#include <sqlite3.h>
|
||||
|
||||
@@ -24,8 +24,10 @@ typedef union FFvariant
|
||||
|
||||
FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type);
|
||||
FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type);
|
||||
FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type);
|
||||
FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type);
|
||||
FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type);
|
||||
typedef bool FFTestXfconfPropCallback(void* data, const char* propertyName); // Return false to break loop
|
||||
FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb);
|
||||
|
||||
int ffSettingsGetSQLite3Int(const char* dbPath, const char* query);
|
||||
bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result);
|
||||
|
||||
@@ -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, true);
|
||||
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
|
||||
|
||||
+164
-888
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
|
||||
{
|
||||
|
||||
@@ -5,69 +5,55 @@
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
io_registry_entry_t registryEntry;
|
||||
|
||||
#ifndef __aarch64__
|
||||
|
||||
//https://github.com/osquery/osquery/blob/master/osquery/tables/system/darwin/smbios_tables.cpp
|
||||
//For Intel
|
||||
if((registryEntry = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/rom")))
|
||||
{
|
||||
CFMutableDictionaryRef properties;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
{
|
||||
IOObjectRelease(registryEntry);
|
||||
return "IORegistryEntryCreateCFProperties(registryEntry) failed";
|
||||
}
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceRom = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/rom");
|
||||
if (!deviceRom)
|
||||
return "IODeviceTree:/rom not found";
|
||||
|
||||
ffCfDictGetString(properties, CFSTR("vendor"), &bios->vendor);
|
||||
ffCfDictGetString(properties, CFSTR("version"), &bios->version);
|
||||
ffCfDictGetString(properties, CFSTR("release-date"), &bios->date);
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef deviceRomProps = NULL;
|
||||
if(IORegistryEntryCreateCFProperties(deviceRom, &deviceRomProps, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
return "IORegistryEntryCreateCFProperties(deviceRom) failed";
|
||||
|
||||
CFRelease(properties);
|
||||
IOObjectRelease(registryEntry);
|
||||
return NULL;
|
||||
}
|
||||
ffCfDictGetString(deviceRomProps, CFSTR("vendor"), &bios->vendor);
|
||||
ffCfDictGetString(deviceRomProps, CFSTR("version"), &bios->version);
|
||||
ffCfDictGetString(deviceRomProps, CFSTR("release-date"), &bios->date);
|
||||
ffStrbufSetStatic(&bios->type, "UEFI");
|
||||
|
||||
#else
|
||||
|
||||
//For arm64
|
||||
if((registryEntry = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/")))
|
||||
{
|
||||
CFMutableDictionaryRef properties;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) == kIOReturnSuccess)
|
||||
{
|
||||
ffCfDictGetString(properties, CFSTR("manufacturer"), &bios->vendor);
|
||||
ffCfDictGetString(properties, CFSTR("time-stamp"), &bios->date);
|
||||
CFRelease(properties);
|
||||
}
|
||||
IOObjectRelease(registryEntry);
|
||||
}
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t device = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/");
|
||||
if (!device)
|
||||
return "IODeviceTree:/ not found";
|
||||
|
||||
if((registryEntry = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen")))
|
||||
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef deviceProps = NULL;
|
||||
if(IORegistryEntryCreateCFProperties(device, &deviceProps, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
return "IORegistryEntryCreateCFProperties(device) failed";
|
||||
|
||||
ffCfDictGetString(deviceProps, CFSTR("manufacturer"), &bios->vendor);
|
||||
ffCfDictGetString(deviceProps, CFSTR("time-stamp"), &bios->date);
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceChosen = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
|
||||
if (deviceChosen)
|
||||
{
|
||||
CFMutableDictionaryRef properties;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) == kIOReturnSuccess)
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef systemFirmWareVersion = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (systemFirmWareVersion)
|
||||
{
|
||||
ffCfDictGetString(properties, CFSTR("system-firmware-version"), &bios->version);
|
||||
ffCfStrGetString(systemFirmWareVersion, &bios->version);
|
||||
uint32_t index = ffStrbufFirstIndexC(&bios->version, '-');
|
||||
if (index != bios->version.length)
|
||||
{
|
||||
ffStrbufAppendNS(&bios->type, index, bios->version.chars);
|
||||
ffStrbufRemoveSubstr(&bios->version, 0, index + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufSetStatic(&bios->type, "iBoot");
|
||||
}
|
||||
CFRelease(properties);
|
||||
}
|
||||
IOObjectRelease(registryEntry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!bios->type.length)
|
||||
ffStrbufSetStatic(&bios->type, "iBoot");
|
||||
#endif
|
||||
|
||||
return "Failed to query bios info";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bluetooth/option.h"
|
||||
|
||||
typedef struct FFBluetoothResult
|
||||
{
|
||||
|
||||
@@ -196,7 +196,7 @@ static const char* detectBluetooth(FFlist* devices, int32_t connectedCount)
|
||||
if(error)
|
||||
return error;
|
||||
|
||||
DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL);
|
||||
DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL, NULL);
|
||||
if(!managedObjects)
|
||||
return "Failed to call GetManagedObjects";
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/bluetoothradio/option.h"
|
||||
|
||||
typedef struct FFBluetoothRadioResult
|
||||
{
|
||||
|
||||
@@ -77,7 +77,7 @@ static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const cha
|
||||
char objPath[300];
|
||||
snprintf(objPath, sizeof(objPath), "/org/bluez/%s", hciName);
|
||||
|
||||
DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1");
|
||||
DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1", NULL);
|
||||
if(!properties)
|
||||
return "Failed to call org.freedesktop.DBus.Properties.GetAll";
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ static const char* detectWithDisplayServices(const FFDisplayServerResult* displa
|
||||
// Works for Apple Silicon and USB-C adapter connection ( but not HTMI )
|
||||
static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult* displayServer, FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
if (!IOAVServiceCreate || !IOAVServiceReadI2C)
|
||||
if (!IOAVServiceCreate || !IOAVServiceReadI2C || !IOAVServiceWriteI2C)
|
||||
return "IOAVService is not available";
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
@@ -123,65 +123,100 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult*
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static IOOptionBits getSupportedTransactionType(void)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceNameMatching("IOFramebufferI2CInterface"), &iterator) != KERN_SUCCESS)
|
||||
return kIOI2CNoTransactionType;
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != MACH_PORT_NULL)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_service_t io_service = registryEntry;
|
||||
FF_CFTYPE_AUTO_RELEASE CFNumberRef IOI2CTransactionTypes = IORegistryEntryCreateCFProperty(io_service, CFSTR(kIOI2CTransactionTypesKey), kCFAllocatorDefault, kNilOptions);
|
||||
|
||||
if (IOI2CTransactionTypes)
|
||||
{
|
||||
int64_t types = 0;
|
||||
ffCfNumGetInt64(IOI2CTransactionTypes, &types);
|
||||
|
||||
if (types) {
|
||||
if ((1 << kIOI2CDDCciReplyTransactionType) & (uint64_t) types)
|
||||
return kIOI2CDDCciReplyTransactionType;
|
||||
if ((1 << kIOI2CSimpleTransactionType) & (uint64_t) types)
|
||||
return kIOI2CSimpleTransactionType;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return kIOI2CNoTransactionType;
|
||||
}
|
||||
|
||||
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFBrightnessOptions* options, FFlist* result)
|
||||
{
|
||||
if (!CGSServiceForDisplayNumber) return "CGSServiceForDisplayNumber is not available";
|
||||
IOOptionBits transactionType = getSupportedTransactionType();
|
||||
if (transactionType == kIOI2CNoTransactionType)
|
||||
return "No supported IOI2C transaction type found";
|
||||
|
||||
FF_LIST_FOR_EACH(FFDisplayResult, display, displayServer->displays)
|
||||
{
|
||||
if (display->type == FF_DISPLAY_TYPE_EXTERNAL)
|
||||
{
|
||||
io_service_t framebuffer = 0;
|
||||
FF_IOOBJECT_AUTO_RELEASE io_service_t framebuffer = IO_OBJECT_NULL;
|
||||
CGSServiceForDisplayNumber((CGDirectDisplayID)display->id, &framebuffer);
|
||||
if (framebuffer == 0) continue;
|
||||
if (framebuffer == IO_OBJECT_NULL) continue;
|
||||
|
||||
IOItemCount count;
|
||||
if (IOFBGetI2CInterfaceCount(framebuffer, &count) != KERN_SUCCESS || count == 0) continue;
|
||||
|
||||
io_service_t interface = 0;
|
||||
if (IOFBCopyI2CInterfaceForBus(framebuffer, 0, &interface) != KERN_SUCCESS) continue;
|
||||
|
||||
uint8_t i2cOut[12] = {};
|
||||
IOI2CConnectRef connect;
|
||||
if (IOI2CInterfaceOpen(interface, kNilOptions, &connect) != KERN_SUCCESS)
|
||||
{
|
||||
IOObjectRelease(interface);
|
||||
if (IOFBGetI2CInterfaceCount(framebuffer, &count) != KERN_SUCCESS || count == 0)
|
||||
continue;
|
||||
|
||||
for (IOItemCount bus = 0; bus < count; ++bus)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_service_t interface = IO_OBJECT_NULL;
|
||||
if (IOFBCopyI2CInterfaceForBus(framebuffer, bus, &interface) != KERN_SUCCESS) continue;
|
||||
|
||||
uint8_t i2cOut[12] = {};
|
||||
IOI2CConnectRef connect = NULL;
|
||||
if (IOI2CInterfaceOpen(interface, kNilOptions, &connect) != KERN_SUCCESS)
|
||||
continue;
|
||||
|
||||
uint8_t i2cIn[] = { 0x51, 0x82, 0x01, 0x10 /* luminance */, 0 };
|
||||
i2cIn[4] = 0x6E ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
|
||||
|
||||
IOI2CRequest request = {
|
||||
.commFlags = kNilOptions,
|
||||
.sendAddress = 0x6e,
|
||||
.sendTransactionType = kIOI2CSimpleTransactionType,
|
||||
.sendBuffer = (vm_address_t) i2cIn,
|
||||
.sendBytes = ARRAY_SIZE(i2cIn),
|
||||
.minReplyDelay = options->ddcciSleep * 1000ULL,
|
||||
.replyAddress = 0x6F,
|
||||
.replySubAddress = 0x51,
|
||||
.replyTransactionType = transactionType,
|
||||
.replyBytes = ARRAY_SIZE(i2cOut),
|
||||
.replyBuffer = (vm_address_t) i2cOut,
|
||||
};
|
||||
IOReturn ret = IOI2CSendRequest(connect, kNilOptions, &request);
|
||||
IOI2CInterfaceClose(connect, kNilOptions);
|
||||
|
||||
if (ret != KERN_SUCCESS || request.result != kIOReturnSuccess || request.replyBytes < 10) continue;
|
||||
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) continue;
|
||||
|
||||
uint32_t current = ((uint32_t) i2cOut[8] << 8u) + (uint32_t) i2cOut[9];
|
||||
uint32_t max = ((uint32_t) i2cOut[6] << 8u) + (uint32_t) i2cOut[7];
|
||||
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
brightness->max = max;
|
||||
brightness->min = 0;
|
||||
brightness->current = current;
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
brightness->builtin = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t i2cIn[] = { 0x51, 0x82, 0x01, 0x10 /* luminance */, 0 };
|
||||
i2cIn[4] = 0x6E ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
|
||||
|
||||
IOI2CRequest request = {
|
||||
.commFlags = kNilOptions,
|
||||
.sendAddress = 0x6e,
|
||||
.sendTransactionType = kIOI2CSimpleTransactionType,
|
||||
.sendBuffer = (vm_address_t) i2cIn,
|
||||
.sendBytes = ARRAY_SIZE(i2cIn),
|
||||
.minReplyDelay = options->ddcciSleep,
|
||||
.replyAddress = 0x6F,
|
||||
.replySubAddress = 0x51,
|
||||
.replyTransactionType = kIOI2CDDCciReplyTransactionType,
|
||||
.replyBytes = ARRAY_SIZE(i2cOut),
|
||||
.replyBuffer = (vm_address_t) i2cOut,
|
||||
};
|
||||
IOReturn ret = IOI2CSendRequest(connect, kNilOptions, &request);
|
||||
IOI2CInterfaceClose(connect, kNilOptions);
|
||||
IOObjectRelease(interface);
|
||||
|
||||
if (ret != KERN_SUCCESS || request.result != kIOReturnSuccess) continue;
|
||||
|
||||
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) continue;
|
||||
|
||||
uint32_t current = ((uint32_t) i2cOut[8] << 8u) + (uint32_t) i2cOut[9];
|
||||
uint32_t max = ((uint32_t) i2cOut[6] << 8u) + (uint32_t) i2cOut[7];
|
||||
|
||||
FFBrightnessResult* brightness = (FFBrightnessResult*) ffListAdd(result);
|
||||
brightness->max = max;
|
||||
brightness->min = 0;
|
||||
brightness->current = current;
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
brightness->builtin = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,13 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/btrfs/option.h"
|
||||
|
||||
typedef struct FFBtrfsDiskUsage
|
||||
{
|
||||
uint64_t total;
|
||||
uint64_t used;
|
||||
const char* type;
|
||||
bool dup;
|
||||
const char* profile; // single / dup / raidx
|
||||
uint8_t copies;
|
||||
} FFBtrfsDiskUsage;
|
||||
|
||||
typedef struct FFBtrfsResult
|
||||
|
||||
@@ -73,20 +73,40 @@ static const char* detectAllocation(FFBtrfsResult* item, int dfd, FFstrbuf* buff
|
||||
item->globalReservationUsed = ffStrbufToUInt(buffer, 0);
|
||||
item->globalReservationUsed = item->globalReservationTotal - item->globalReservationUsed;
|
||||
|
||||
#define FF_BTRFS_DETECT_TYPE(index, _type) \
|
||||
if (ffReadFileBufferRelative(subfd, #_type "/total_bytes", buffer)) \
|
||||
item->allocation[index].total = ffStrbufToUInt(buffer, 0); \
|
||||
\
|
||||
if (ffReadFileBufferRelative(subfd, #_type "/bytes_used", buffer)) \
|
||||
item->allocation[index].used = ffStrbufToUInt(buffer, 0); \
|
||||
\
|
||||
item->allocation[index].dup = faccessat(subfd, #_type "/dup/", F_OK, 0) == 0; \
|
||||
\
|
||||
item->allocation[index].type = #_type;
|
||||
#define FF_BTRFS_DETECT_PROFILE(_index, _type, _profile, _copies) \
|
||||
else if (faccessat(subfd, _type "/" _profile "/", F_OK, 0) == 0) { \
|
||||
item->allocation[_index].profile = _profile; \
|
||||
item->allocation[_index].copies = _copies; \
|
||||
}
|
||||
|
||||
FF_BTRFS_DETECT_TYPE(0, data);
|
||||
FF_BTRFS_DETECT_TYPE(1, metadata);
|
||||
FF_BTRFS_DETECT_TYPE(2, system);
|
||||
#define FF_BTRFS_DETECT_TYPE(_index, _type) \
|
||||
do { \
|
||||
item->allocation[_index].type = _type; \
|
||||
if (ffReadFileBufferRelative(subfd, _type "/total_bytes", buffer)) \
|
||||
item->allocation[_index].total = ffStrbufToUInt(buffer, 0); \
|
||||
\
|
||||
if (ffReadFileBufferRelative(subfd, _type "/bytes_used", buffer)) \
|
||||
item->allocation[_index].used = ffStrbufToUInt(buffer, 0); \
|
||||
\
|
||||
if (false) {} \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "single", 1) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "dup", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid0", 1) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid10", 2) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c3", 3) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c4", 4) \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid5", 1) /* (n-1)/n */ \
|
||||
FF_BTRFS_DETECT_PROFILE(_index, _type, "raid6", 1) /* (n-2)/n */ \
|
||||
else { \
|
||||
item->allocation[_index].profile = "unknown"; \
|
||||
item->allocation[_index].copies = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
FF_BTRFS_DETECT_TYPE(0, "data");
|
||||
FF_BTRFS_DETECT_TYPE(1, "metadata");
|
||||
FF_BTRFS_DETECT_TYPE(2, "system");
|
||||
|
||||
#undef FF_BTRFS_DETECT_TYPE
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#include "common/processing.h"
|
||||
#include "util/FFstrbuf.h"
|
||||
#include "detection/command/command.h"
|
||||
|
||||
typedef struct FFCommandResultBundle
|
||||
{
|
||||
FFProcessHandle handle;
|
||||
const char* error;
|
||||
} FFCommandResultBundle;
|
||||
|
||||
// FIFO, non-thread-safe list of running commands
|
||||
static FFlist commandQueue = {
|
||||
.elementSize = sizeof(FFCommandResultBundle),
|
||||
};
|
||||
|
||||
static const char* spawnProcess(FFCommandOptions* options, FFProcessHandle* handle)
|
||||
{
|
||||
if (options->text.length == 0)
|
||||
return "No command text specified";
|
||||
|
||||
return ffProcessSpawn(options->param.length ? (char* const[]){
|
||||
options->shell.chars,
|
||||
options->param.chars,
|
||||
options->text.chars,
|
||||
NULL
|
||||
} : (char* const[]){
|
||||
options->shell.chars,
|
||||
options->text.chars,
|
||||
NULL
|
||||
}, options->useStdErr, handle);
|
||||
}
|
||||
|
||||
bool ffPrepareCommand(FFCommandOptions* options)
|
||||
{
|
||||
if (!options->parallel) return false;
|
||||
|
||||
FFCommandResultBundle* bundle = ffListAdd(&commandQueue);
|
||||
bundle->error = spawnProcess(options, &bundle->handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ffDetectCommand(FFCommandOptions* options, FFstrbuf* result)
|
||||
{
|
||||
FFCommandResultBundle bundle = {};
|
||||
if (!options->parallel)
|
||||
bundle.error = spawnProcess(options, &bundle.handle);
|
||||
else if (!ffListShift(&commandQueue, &bundle))
|
||||
return "[BUG] command queue is empty";
|
||||
|
||||
if (bundle.error)
|
||||
return bundle.error;
|
||||
|
||||
bundle.error = ffProcessReadOutput(&bundle.handle, result);
|
||||
if (bundle.error)
|
||||
return bundle.error;
|
||||
|
||||
ffStrbufTrimRightSpace(result);
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/command/option.h"
|
||||
|
||||
const char* ffDetectCommand(FFCommandOptions* options, FFstrbuf* result);
|
||||
@@ -60,3 +60,446 @@ 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>
|
||||
|
||||
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 & (1 << 0) /* HWCAP_FP */) != 0;
|
||||
bool has_asimd = (hwcap & (1 << 1) /* HWCAP_ASIMD */) != 0;
|
||||
|
||||
// ARMv8.1-A
|
||||
bool has_atomics = (hwcap & (1 << 8) /* HWCAP_ATOMICS */) != 0; // optional from v8.0
|
||||
bool has_crc32 = (hwcap & (1 << 7) /* HWCAP_CRC32 */) != 0; // optional from v8.0
|
||||
bool has_asimdrdm = (hwcap & (1 << 12) /* HWCAP_ASIMDRDM */) != 0; // optional from v8.0
|
||||
|
||||
// ARMv8.2-A
|
||||
bool has_fphp = (hwcap & (1 << 9) /* HWCAP_FPHP */) != 0; // optional
|
||||
bool has_dcpop = (hwcap & (1 << 16) /* HWCAP_DCPOP */) != 0; // DC CVAP, optional from v8.1
|
||||
|
||||
// ARMv8.3-A
|
||||
bool has_paca = (hwcap & (1 << 30) /* HWCAP_PACA */) != 0; // optional from v8.2
|
||||
bool has_lrcpc = (hwcap & (1 << 15) /* HWCAP_LRCPC */) != 0; // optional from v8.2
|
||||
bool has_fcma = (hwcap & (1 << 14) /* HWCAP_FCMA */) != 0; // optional from v8.2
|
||||
bool has_jscvt = (hwcap & (1 << 13) /* HWCAP_JSCVT */) != 0; // optional from v8.2
|
||||
|
||||
// ARMv8.4-A
|
||||
bool has_dit = (hwcap & (1 << 24) /* HWCAP_DIT */) != 0; // optional from v8.3
|
||||
bool has_flagm = (hwcap & (1 << 27) /* HWCAP_FLAGM */) != 0; // optional from v8.1
|
||||
bool has_ilrcpc = (hwcap & (1 << 26) /* HWCAP_ILRCPC */) != 0; // optional from v8.2
|
||||
|
||||
// ARMv8.5-A
|
||||
bool has_bti = (hwcap2 & (1 << 17) /* HWCAP2_BTI */) != 0; // optional from v8.4
|
||||
bool has_sb = (hwcap & (1 << 29) /* HWCAP_SB */) != 0; // optional from v8.0
|
||||
bool has_dcpodp = (hwcap2 & (1 << 0) /* HWCAP2_DCPODP */) != 0; // optional from v8.1
|
||||
bool has_flagm2 = (hwcap2 & (1 << 7) /* HWCAP2_FLAGM2 */) != 0; // optional from v8.4
|
||||
bool has_frint = (hwcap2 & (1 << 8) /* HWCAP2_FRINT */) != 0; // optional from v8.4
|
||||
|
||||
// ARMv9.0-A
|
||||
bool has_sve2 = (hwcap2 & (1 << 1) /* HWCAP2_SVE2 */) != 0;
|
||||
|
||||
// ARMv9.1-A
|
||||
// ARMv8.6-A
|
||||
bool has_bf16 = (hwcap2 & (1 << 14) /* HWCAP2_BF16 */) != 0; // optional from v8.2
|
||||
bool has_i8mm = (hwcap2 & (1 << 13) /* HWCAP2_I8MM */) != 0; // optional from v8.1
|
||||
|
||||
// ARMv8.7-A
|
||||
bool has_afp = (hwcap2 & (1 << 20) /* HWCAP2_AFP */) != 0; // optional from v8.6
|
||||
|
||||
// ARMv9.2-A
|
||||
bool has_sme = (hwcap2 & (1 << 23) /* HWCAP2_SME */) != 0;
|
||||
|
||||
// ARMv9.3-A
|
||||
bool has_sme2 = (hwcap2 & (1UL << 37) /* HWCAP2_SME2 */) != 0; // optional from v9.2
|
||||
|
||||
// ARMv8.8-A
|
||||
bool has_mops = (hwcap2 & (1UL << 43) /* HWCAP2_MOPS */) != 0; // optional from v8.7
|
||||
|
||||
// ARMv8.9-A
|
||||
bool has_cssc = (hwcap2 & (1UL << 34) /* HWCAP2_CSSC */) != 0; // optional from v8.7
|
||||
|
||||
// ARMv9.4-A
|
||||
bool has_sme2p1 = (hwcap2 & (1UL << 38) /* HWCAP2_SME2P1 */) != 0; // optional from v9.2
|
||||
|
||||
// ARMv9.5-A
|
||||
bool has_f8e4m3 = (hwcap2 & (1UL << 55) /* HWCAP2_F8E4M3 */) != 0; // optional from v9.2
|
||||
bool has_f8e5m2 = (hwcap2 & (1UL << 56) /* HWCAP2_F8E5M2 */) != 0; // optional from v9.2
|
||||
|
||||
// ARMv9.6-A
|
||||
bool has_cmpbr = (hwcap & (1UL << 33) /* HWCAP_CMPBR */) != 0; // optional from v9.5
|
||||
bool has_fprcvt = (hwcap & (1UL << 34) /* 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> // Not available in macOS 14-
|
||||
|
||||
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(50); /* CAP_BIT_AdvSIMD_HPFPCvt */ // Full FP16 support (implies FP/ASIMD)
|
||||
bool has_asimd = FF_HAS_CAP(49); /* CAP_BIT_AdvSIMD */ // Advanced SIMD (NEON)
|
||||
|
||||
// ARMv8.1-A
|
||||
bool has_lse = FF_HAS_CAP(6); /* CAP_BIT_FEAT_LSE */ // Large System Extensions, optional in v8.0
|
||||
bool has_crc32 = FF_HAS_CAP(51); /* CAP_BIT_FEAT_CRC32 */ // CRC32 instructions, optional in v8.0
|
||||
bool has_rdm = FF_HAS_CAP(5); /* CAP_BIT_FEAT_RDM */ // AdvSIMD rounding double multiply accumulate, optional in v8.0
|
||||
|
||||
// ARMv8.2-A
|
||||
bool has_fp16 = FF_HAS_CAP(34); /* CAP_BIT_FEAT_FP16 */ // Half-precision FP support, optional
|
||||
bool has_dpb = FF_HAS_CAP(22); /* CAP_BIT_FEAT_DPB */ // DC CVAP, optional from v8.1
|
||||
|
||||
// ARMv8.3-A
|
||||
bool has_pauth = FF_HAS_CAP(19); /* CAP_BIT_FEAT_PAuth */ // Pointer Authentication (PAC), optional from v8.2
|
||||
bool has_lrcpc = FF_HAS_CAP(15); /* CAP_BIT_FEAT_LRCPC */ // LDAPR/LR with RCPC semantics, optional from v8.2
|
||||
bool has_fcma = FF_HAS_CAP(17); /* CAP_BIT_FEAT_FCMA */ // Complex number multiply-add, optional from v8.2
|
||||
bool has_jscvt = FF_HAS_CAP(18); /* CAP_BIT_FEAT_JSCVT */ // JavaScript-style conversion (FJCVTZS), optional from v8.2
|
||||
|
||||
// ARMv8.4-A
|
||||
bool has_lse2 = FF_HAS_CAP(30); /* CAP_BIT_FEAT_LSE2 */ // Large System Extensions version 2, optional from v8.2
|
||||
bool has_dit = FF_HAS_CAP(33); /* CAP_BIT_FEAT_DIT */ // Data Independent Timing, optional from v8.3
|
||||
bool has_flagm = FF_HAS_CAP(0); /* CAP_BIT_FEAT_FlagM */ // Flag manipulation (FMOV/FCVT), optional from v8.1
|
||||
bool has_lrcpc2 = FF_HAS_CAP(16); /* CAP_BIT_FEAT_LRCPC2 */ // Enhanced RCPC (LDAPUR/LDAPST), optional from v8.2
|
||||
|
||||
// ARMv8.5-A
|
||||
bool has_bti = FF_HAS_CAP(36); /* CAP_BIT_FEAT_BTI */ // Branch Target Identification, optional from v8.4
|
||||
bool has_sb = FF_HAS_CAP(13); /* CAP_BIT_FEAT_SB */ // Speculative Barrier, optional from v8.0
|
||||
bool has_dpb2 = FF_HAS_CAP(23); /* CAP_BIT_FEAT_DPB2 */ // DC CVADP (DPB2), optional from v8.1
|
||||
bool has_flagm2 = FF_HAS_CAP(1); /* CAP_BIT_FEAT_FlagM2 */ // Enhanced FlagM, optional from v8.4
|
||||
bool has_frintts = FF_HAS_CAP(14); /* 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(24); /* CAP_BIT_FEAT_BF16 */ // Brain float16, optional from v8.2
|
||||
bool has_i8mm = FF_HAS_CAP(25); /* CAP_BIT_FEAT_I8MM */ // Int8 Matrix Multiply, optional from v8.1
|
||||
|
||||
// ARMv8.7-A
|
||||
bool has_afp = FF_HAS_CAP(29); /* CAP_BIT_FEAT_AFP */ // Alternate FP16 (FEXPA), optional from v8.6
|
||||
|
||||
// ARMv9.2-A
|
||||
bool has_sme = FF_HAS_CAP(40); /* CAP_BIT_FEAT_SME */ // Scalable Matrix Extension, optional from v9.2
|
||||
|
||||
// ARMv9.3-A
|
||||
bool has_sme2 = FF_HAS_CAP(41); /* CAP_BIT_FEAT_SME2 */ // SME2, optional from v9.2
|
||||
|
||||
// ARMv8.8-A
|
||||
bool has_hbc = FF_HAS_CAP(64); /* CAP_BIT_FEAT_HBC */ // Hinted conditional branches, optional from v8.7
|
||||
|
||||
// ARMv8.9-A
|
||||
bool has_cssc = FF_HAS_CAP(67); /* 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 && has_lse2) {
|
||||
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);
|
||||
|
||||
@@ -39,7 +39,7 @@ static const char* detectFrequency(FFCPUResult* cpu)
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("pmgr"));
|
||||
if (!entryDevice)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
return "IOServiceGetMatchingService() failed";
|
||||
|
||||
if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice"))
|
||||
return "\"pmgr\" should conform to \"AppleARMIODevice\"";
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -112,8 +112,12 @@ static const char* armPartId2name(uint32_t partId)
|
||||
case 0xd87: return "Cortex-A725";
|
||||
case 0xd88: return "Cortex-A520AE";
|
||||
case 0xd89: return "Cortex-A720AE";
|
||||
case 0xd8a: return "C1-Nano";
|
||||
case 0xd8b: return "C1-Pro";
|
||||
case 0xd8c: return "C1-Ultra";
|
||||
case 0xd8e: return "Neoverse-N3";
|
||||
case 0xd8f: return "Cortex-A320";
|
||||
case 0xd90: return "C1-Premium";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
@@ -213,6 +217,7 @@ static const char* nvidiaPartId2name(uint32_t partId)
|
||||
case 0x000: return "Denver";
|
||||
case 0x003: return "Denver 2";
|
||||
case 0x004: return "Carmel";
|
||||
case 0x010: return "Olympus";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
+280
-143
@@ -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,119 @@ 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]");
|
||||
assert(cpu->name.length >= 2);
|
||||
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 8845: name = "8 Gen 5"; break; // ?
|
||||
case 8850: name = "8 Elite Gen 5"; break;
|
||||
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]");
|
||||
assert(cpu->name.length >= 2);
|
||||
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 6993: name = "9500"; break;
|
||||
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 detectExynos(FFCPUResult* cpu)
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/Exynos
|
||||
|
||||
assert(cpu->name.length > 3);
|
||||
uint32_t code = (uint32_t) strtoul(cpu->name.chars + 3, NULL, 10);
|
||||
const char* name = NULL;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case 9955: name = "2500"; break;
|
||||
case 9945: name = "2400"; break;
|
||||
// No 2300
|
||||
case 9925: name = "2200"; break;
|
||||
case 9840: name = "2100"; break;
|
||||
|
||||
case 8855: name = "1580"; break;
|
||||
case 8845: name = "1480"; break;
|
||||
case 8835: name = "1380"; break;
|
||||
case 8535: name = "1330"; break;
|
||||
case 8825: name = "1280"; break;
|
||||
case 9815: name = "1080"; break;
|
||||
|
||||
case 9830: name = "990"; break;
|
||||
case 9630: name = "980"; break;
|
||||
|
||||
case 8805: name = "880"; break;
|
||||
case 3830: name = "850"; break;
|
||||
}
|
||||
|
||||
if (name)
|
||||
{
|
||||
char str[32];
|
||||
ffStrCopy(str, cpu->name.chars, sizeof(str));
|
||||
ffStrbufSetF(&cpu->name, "Samsung Exynos %s [%s]", name, str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void detectAndroid(FFCPUResult* cpu)
|
||||
@@ -187,19 +266,33 @@ static void detectAndroid(FFCPUResult* cpu)
|
||||
{
|
||||
if (ffSettingsGetAndroidProperty("ro.soc.model", &cpu->name))
|
||||
ffStrbufClear(&cpu->vendor); // We usually detect the vendor of CPU core as ARM, but instead we want the vendor of SOC
|
||||
else if(ffSettingsGetAndroidProperty("ro.mediatek.platform", &cpu->name))
|
||||
ffStrbufSetStatic(&cpu->vendor, "MTK");
|
||||
}
|
||||
if (cpu->vendor.length == 0)
|
||||
{
|
||||
if (!ffSettingsGetAndroidProperty("ro.soc.manufacturer", &cpu->vendor))
|
||||
ffSettingsGetAndroidProperty("ro.product.product.manufacturer", &cpu->vendor);
|
||||
if (!ffSettingsGetAndroidProperty("ro.product.product.manufacturer", &cpu->vendor))
|
||||
if (!ffSettingsGetAndroidProperty("ro.product.vendor.manufacturer", &cpu->vendor))
|
||||
if(ffSettingsGetAndroidProperty("ro.mediatek.platform", &cpu->name))
|
||||
ffStrbufSetStatic(&cpu->vendor, "MediaTek");
|
||||
}
|
||||
|
||||
if (ffStrbufEqualS(&cpu->vendor, "QTI") && ffStrbufStartsWithS(&cpu->name, "SM"))
|
||||
if (ffStrbufEqualS(&cpu->vendor, "QTI"))
|
||||
ffStrbufSetStatic(&cpu->vendor, "Qualcomm");
|
||||
else if (ffStrbufIgnCaseEqualS(&cpu->vendor, "MediaTek")) // sometimes "Mediatek"
|
||||
ffStrbufSetStatic(&cpu->vendor, "MediaTek");
|
||||
else if (cpu->vendor.length > 0)
|
||||
cpu->vendor.chars[0] = (char) toupper(cpu->vendor.chars[0]);
|
||||
|
||||
if (ffStrbufEqualS(&cpu->vendor, "Qualcomm") && ffStrbufStartsWithS(&cpu->name, "SM"))
|
||||
detectQualcomm(cpu);
|
||||
else if (ffStrbufEqualS(&cpu->vendor, "MTK") && ffStrbufStartsWithS(&cpu->name, "MT"))
|
||||
else if (ffStrbufEqualS(&cpu->vendor, "MediaTek") && ffStrbufStartsWithS(&cpu->name, "MT"))
|
||||
detectMediaTek(cpu);
|
||||
else if (ffStrbufEqualS(&cpu->vendor, "Samsung") && ffStrbufStartsWithS(&cpu->name, "s5e"))
|
||||
{
|
||||
cpu->name.chars[0] = 'S';
|
||||
cpu->name.chars[2] = 'E';
|
||||
detectExynos(cpu);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -318,6 +411,14 @@ static const char* parseCpuInfo(
|
||||
(cpu->name.length == 0 && ffParsePropLine(line, "processor 0:", &cpu->name)) ||
|
||||
(cpu->vendor.length == 0 && ffParsePropLine(line, "vendor_id :", &cpu->vendor)) ||
|
||||
(cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz static :", cpuMHz)) || // This one cannot be detected because of early return
|
||||
#elif __ia64__
|
||||
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
|
||||
(cpu->vendor.length == 0 && ffParsePropLine(line, "vendor :", &cpu->vendor)) ||
|
||||
(cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz :", cpuMHz)) ||
|
||||
#elif __hppa__
|
||||
(cpu->name.length == 0 && ffParsePropLine(line, "cpu :", &cpu->name)) ||
|
||||
#elif __sh__
|
||||
(cpu->name.length == 0 && ffParsePropLine(line, "cpu type :", &cpu->name)) ||
|
||||
#else
|
||||
(cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) ||
|
||||
(cpu->name.length == 0 && ffParsePropLine(line, "model :", &cpu->name)) ||
|
||||
@@ -463,7 +564,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);
|
||||
|
||||
@@ -575,19 +676,46 @@ FF_MAYBE_UNUSED static void detectSocName(FFCPUResult* cpu)
|
||||
if (cpu->name.length > 0)
|
||||
return;
|
||||
|
||||
// device-vendor,device-model\0soc-vendor,soc-model\0
|
||||
char content[256];
|
||||
// [x-vendor,x-model\0]*N
|
||||
char content[512];
|
||||
ssize_t length = ffReadFileData("/proc/device-tree/compatible", ARRAY_SIZE(content), content);
|
||||
if (length <= 2) return;
|
||||
if (length < 4) return; // v,m\0
|
||||
|
||||
// get the second NUL terminated string if it exists
|
||||
char* vendor = memchr(content, '\0', (size_t) length) + 1;
|
||||
if (!vendor || vendor - content >= length) vendor = content;
|
||||
if (content[length - 1] != '\0') return; // must end with \0
|
||||
|
||||
char* model = strchr(vendor, ',');
|
||||
if (!model) return;
|
||||
*model = '\0';
|
||||
++model;
|
||||
--length;
|
||||
|
||||
char* vendor = NULL;
|
||||
char* model = NULL;
|
||||
|
||||
for (char* p; length > 0; length = p ? (ssize_t) (p - content) - 1 : 0)
|
||||
{
|
||||
p = memrchr(content, '\0', (size_t) length);
|
||||
|
||||
vendor = p /* first entry */ ? p + 1 : content;
|
||||
|
||||
size_t partLen = (size_t) (length - (vendor - content));
|
||||
if (partLen < 3) continue;
|
||||
|
||||
char* comma = memchr(vendor, ',', partLen);
|
||||
if (!comma) continue;
|
||||
|
||||
size_t vendorLen = (size_t) (comma - vendor);
|
||||
if (vendorLen == 0) continue;
|
||||
|
||||
model = comma + 1;
|
||||
size_t modelLen = (size_t) (partLen - (size_t) (model - vendor));
|
||||
if (modelLen == 0) continue;
|
||||
|
||||
if ((modelLen >= strlen("-platform") && ffStrEndsWith(model, "-platform")) ||
|
||||
(modelLen >= strlen("-soc") && ffStrEndsWith(model, "-soc")))
|
||||
continue;
|
||||
|
||||
*comma = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
if (!length) return;
|
||||
|
||||
if (false) {}
|
||||
#if __aarch64__
|
||||
@@ -643,6 +771,13 @@ FF_MAYBE_UNUSED static void detectSocName(FFCPUResult* cpu)
|
||||
for (const char* p = model; *p; ++p)
|
||||
ffStrbufAppendC(&cpu->name, (char) toupper(*p));
|
||||
}
|
||||
else if (ffStrEquals(vendor, "thead"))
|
||||
{
|
||||
// Lichee Pi?
|
||||
ffStrbufSetStatic(&cpu->vendor, "T-Head");
|
||||
for (const char* p = model; *p; ++p)
|
||||
ffStrbufAppendC(&cpu->name, (char) toupper(*p));
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufSetS(&cpu->name, model);
|
||||
@@ -741,6 +876,8 @@ FF_MAYBE_UNUSED static const char* detectCPUOthers(const FFCPUOptions* options,
|
||||
if (cpu->coresPhysical == 0)
|
||||
detectPhysicalCores(cpu);
|
||||
|
||||
ffCPUDetectByCpuid(cpu);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user