Merge pull request #1976 from fastfetch-cli/dev

Release: v2.53.0
This commit is contained in:
Carter Li
2025-09-23 09:55:28 +08:00
committed by GitHub
54 changed files with 2834 additions and 1234 deletions
+81 -281
View File
@@ -61,12 +61,19 @@ 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:
@@ -83,25 +90,27 @@ jobs:
run: cat /proc/cpuinfo
- 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 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 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: 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
@@ -126,71 +135,19 @@ jobs:
id: ffversion
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-amd64
path: ./fastfetch-*.*
linux-aarch64:
name: Linux-aarch64
runs-on: ubuntu-22.04-arm
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v5
- name: uname -a
run: uname -a
- name: cat /etc/os-release
run: cat /etc/os-release
- name: cat /proc/cpuinfo
run: cat /proc/cpuinfo
- 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 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
- name: install linuxbrew packages
- name: polyfill glibc
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: 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 .
- 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: ldd fastfetch
- name: run tests
run: ctest --output-on-failure
- name: get fastfetch version
id: ffversion
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
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
cpack
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-aarch64
name: fastfetch-linux-${{ matrix.arch }}
path: ./fastfetch-*.*
linux-armv7l:
@@ -212,11 +169,11 @@ 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 libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
apt-get update && apt-get install -y ca-certificates gpg curl
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 g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -252,7 +209,7 @@ 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 libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -268,12 +225,18 @@ 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@v5
@@ -282,47 +245,12 @@ jobs:
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: riscv64
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 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 .
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-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@v5
- name: run VM
uses: uraimo/run-on-arch-action@v3
id: runcmd
with:
arch: ppc64le
arch: ${{ matrix.arch }}
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 libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
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 libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
@@ -335,42 +263,7 @@ jobs:
- 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@v5
- 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 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:
@@ -411,12 +304,19 @@ 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@v5
@@ -455,54 +355,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@v5
- 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:
@@ -718,12 +571,25 @@ 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}
@@ -734,21 +600,21 @@ jobs:
- 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
@@ -769,101 +635,35 @@ jobs:
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
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-amd64.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
uses: actions/upload-artifact@v4
with:
name: fastfetch-windows-amd64
path: ./fastfetch-windows-amd64.*
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@v5
- name: setup-msys2
uses: msys2/setup-msys2@v2
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
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-aarch64.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
- name: upload 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 }}.*
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-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:
+30
View File
@@ -1,3 +1,33 @@
# 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:
+2 -9
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.52.0
VERSION 2.53.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -1304,10 +1304,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)
@@ -1424,10 +1421,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()
+6
View File
@@ -1,3 +1,9 @@
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
+1 -1
View File
@@ -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
Standards-Version: 4.0.0
Homepage: https://github.com/fastfetch-cli/fastfetch
+1 -1
View File
@@ -1 +1 @@
fastfetch_2.51.0_source.buildinfo universe/utils optional
fastfetch_2.52.0_source.buildinfo universe/utils optional
+104 -9
View File
@@ -2307,17 +2307,60 @@
"const": "disk"
},
"folders": {
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options"
"description": "A list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options",
"oneOf": [
{
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths to get disk usage from",
"default": "/"
},
{
"type": "array",
"description": "An array of folder paths to get disk usage from",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
]
},
"hideFolders": {
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output",
"description": "A list of folder paths to hide from the disk output",
"oneOf": [
{
"type": "string",
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output"
},
{
"type": "array",
"description": "An array of folder paths to hide from the disk output",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
],
"default": "/efi:/boot:/boot/efi:/boot/firmware"
},
"hideFS": {
"type": "string",
"description": "A colon separated file systems to hide from the disk output"
"description": "A list of file systems to hide from the disk output",
"oneOf": [
{
"type": "string",
"description": "A colon separated list of file systems to hide from the disk output"
},
{
"type": "array",
"description": "An array of file systems to hide from the disk output",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
]
},
"showRegular": {
"type": "boolean",
@@ -2593,6 +2636,15 @@
"const": "gamepad",
"description": "List connected gamepads"
},
"ignores": {
"type": "array",
"description": "An array of case-insensitive device name prefixes to ignore",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"percent": {
"$ref": "#/$defs/percent"
},
@@ -2852,6 +2904,15 @@
"const": "keyboard",
"description": "List (connected) keyboards"
},
"ignores": {
"type": "array",
"description": "An array of case-insensitive device name prefixes to ignore",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"key": {
"$ref": "#/$defs/key"
},
@@ -2920,7 +2981,32 @@
},
"showIpv6": {
"description": "Show IPv6 addresses",
"type": "boolean",
"oneOf": [
{
"const": true,
"description": "Show the most useful IPv6 addresses"
},
{
"const": false,
"description": "Do not show IPv6 addresses"
},
{
"const": "gua",
"description": "Show only global unicast IPv6 addresses (2000::/3)"
},
{
"const": "ula",
"description": "Show only unique local IPv6 addresses (fc00::/7)"
},
{
"const": "lla",
"description": "Show only link-local IPv6 addresses (fe80::/10)"
},
{
"const": "unknown",
"description": "Show only IPv6 addresses that are not gua, ula or lla"
}
],
"default": false
},
"showSpeed": {
@@ -3150,6 +3236,15 @@
"const": "mouse",
"description": "List connected mouses"
},
"ignores": {
"type": "array",
"description": "An array of case-insensitive device name prefixes to ignore",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"key": {
"$ref": "#/$defs/key"
},
@@ -3687,8 +3782,8 @@
"description": "Set the color of the separator line",
"$ref": "#/$defs/outputColor"
},
"length": {
"description": "Set the length of the separator line, or 0 to auto-detect",
"times": {
"description": "Set the times of separator string to repeat, or 0 to auto-detect",
"type": "integer",
"minimum": 0,
"default": 0
+1 -1
View File
@@ -1,6 +1,6 @@
// #1887
{
"$schema": "file:///Users/carter/fastfetch/doc/json_schema.json",
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": null,
"display": {
"constants": [
+87
View File
@@ -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
}
]
}
-7
View File
@@ -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"
}
-314
View File
@@ -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;
}
+6
View File
@@ -0,0 +1,6 @@
{
"home": "https://github.com/ridiculousfish/widecharwidth",
"license": "Public domain",
"version": "Unicode 17",
"author": "ridiculousfish"
}
File diff suppressed because it is too large Load Diff
+13 -20
View File
@@ -71,42 +71,35 @@ bool ffParseModuleOptions(const char* key, const char* value)
void ffPrepareCommandOption(FFdata* data)
{
//If we don't have a custom structure, use the default one
if(data->structure.length == 0)
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
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))
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
ffInitDiskIOOptions(&options);
ffPrepareDiskIO(&options);
}
if(ffStrbufContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME))
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
ffInitNetIOOptions(&options);
ffPrepareNetIO(&options);
}
if(instance.config.general.multithreading)
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME, ':'))
{
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
{
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
ffInitPublicIpOptions(&options);
ffPreparePublicIp(&options);
}
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
{
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
}
if(ffStrbufSeparatedContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME, ':'))
{
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
ffInitWeatherOptions(&options);
ffPrepareWeather(&options);
}
}
+35 -63
View File
@@ -132,35 +132,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
#ifdef __linux__
#include "common/io/io.h"
#include <elf.h>
#include <asm/hwcap.h>
#ifndef HWCAP2_SME
#define HWCAP2_SME (1UL << 23)
#endif
#ifndef HWCAP2_SME2
#define HWCAP2_SME2 (1UL << 37)
#endif
#ifndef HWCAP2_CSSC
#define HWCAP2_CSSC (1UL << 34)
#endif
#ifndef HWCAP2_SME2P1
#define HWCAP2_SME2P1 (1UL << 38)
#endif
#ifndef HWCAP2_MOPS
#define HWCAP2_MOPS (1UL << 43)
#endif
#ifndef HWCAP2_F8E4M3
#define HWCAP2_F8E4M3 (1UL << 55)
#endif
#ifndef HWCAP2_F8E5M2
#define HWCAP2_F8E5M2 (1UL << 56)
#endif
#ifndef HWCAP_CMPBR
#define HWCAP_CMPBR (1UL << 33)
#endif
#ifndef HWCAP_FPRCVT
#define HWCAP_FPRCVT (1UL << 34)
#endif
// #include <asm/hwcap.h>
void ffCPUDetectByCpuid(FFCPUResult* cpu)
{
@@ -188,69 +160,69 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
cpu->march = "unknown";
// ARMv8-A
bool has_fp = (hwcap & HWCAP_FP) != 0;
bool has_asimd = (hwcap & HWCAP_ASIMD) != 0;
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 & HWCAP_ATOMICS) != 0; // optional from v8.0
bool has_crc32 = (hwcap & HWCAP_CRC32) != 0; // optional from v8.0
bool has_asimdrdm = (hwcap & HWCAP_ASIMDRDM) != 0; // optional from v8.0
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 & HWCAP_FPHP) != 0; // optional
bool has_dcpop = (hwcap & HWCAP_DCPOP) != 0; // DC CVAP, optional from v8.1
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 & HWCAP_PACA) != 0; // optional from v8.2
bool has_lrcpc = (hwcap & HWCAP_LRCPC) != 0; // optional from v8.2
bool has_fcma = (hwcap & HWCAP_FCMA) != 0; // optional from v8.2
bool has_jscvt = (hwcap & HWCAP_JSCVT) != 0; // optional from v8.2
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 & HWCAP_DIT) != 0; // optional from v8.3
bool has_flagm = (hwcap & HWCAP_FLAGM) != 0; // optional from v8.1
bool has_ilrcpc = (hwcap & HWCAP_ILRCPC) != 0; // optional from v8.2
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 & HWCAP2_BTI) != 0; // optional from v8.4
bool has_sb = (hwcap & HWCAP_SB) != 0; // optional from v8.0
bool has_dcpodp = (hwcap2 & HWCAP2_DCPODP) != 0; // optional from v8.1
bool has_flagm2 = (hwcap2 & HWCAP2_FLAGM2) != 0; // optional from v8.4
bool has_frint = (hwcap2 & HWCAP2_FRINT) != 0; // optional from v8.4
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 & HWCAP2_SVE2) != 0;
bool has_sve2 = (hwcap2 & (1 << 1) /* HWCAP2_SVE2 */) != 0;
// ARMv9.1-A
// ARMv8.6-A
bool has_bf16 = (hwcap2 & HWCAP2_BF16) != 0; // optional from v8.2
bool has_i8mm = (hwcap2 & HWCAP2_I8MM) != 0; // optional from v8.1
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 & HWCAP2_AFP) != 0; // optional from v8.6
bool has_afp = (hwcap2 & (1 << 20) /* HWCAP2_AFP */) != 0; // optional from v8.6
// ARMv9.2-A
bool has_sme = (hwcap2 & HWCAP2_SME) != 0;
bool has_sme = (hwcap2 & (1 << 23) /* HWCAP2_SME */) != 0;
// ARMv9.3-A
bool has_sme2 = (hwcap2 & HWCAP2_SME2) != 0; // optional from v9.2
bool has_sme2 = (hwcap2 & (1UL << 37) /* HWCAP2_SME2 */) != 0; // optional from v9.2
// ARMv8.8-A
bool has_mops = (hwcap2 & HWCAP2_MOPS) != 0; // optional from v8.7
bool has_mops = (hwcap2 & (1UL << 43) /* HWCAP2_MOPS */) != 0; // optional from v8.7
// ARMv8.9-A
bool has_cssc = (hwcap2 & HWCAP2_CSSC) != 0; // optional from v8.7
bool has_cssc = (hwcap2 & (1UL << 34) /* HWCAP2_CSSC */) != 0; // optional from v8.7
// ARMv9.4-A
bool has_sme2p1 = (hwcap2 & HWCAP2_SME2P1) != 0; // optional from v9.2
bool has_sme2p1 = (hwcap2 & (1UL << 38) /* HWCAP2_SME2P1 */) != 0; // optional from v9.2
// ARMv9.5-A
bool has_f8e4m3 = (hwcap2 & HWCAP2_F8E4M3) != 0; // optional from v9.2
bool has_f8e5m2 = (hwcap2 & HWCAP2_F8E5M2) != 0; // optional from v9.2
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 & HWCAP_CMPBR) != 0; // optional from v9.5
bool has_fprcvt = (hwcap & HWCAP_FPRCVT) != 0; // optional from v9.5
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
@@ -457,7 +429,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
// 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_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
@@ -503,7 +475,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu)
cpu->march = "ARMv8.7-A";
} else if (has_i8mm && has_bf16) {
cpu->march = "ARMv8.6-A";
} else if (has_dp) {
} else if (has_dp && has_lse2) {
cpu->march = "ARMv8.4-A";
} else if (has_lrcpc && has_jscvt) {
cpu->march = "ARMv8.3-A";
+5
View File
@@ -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;
}
}
+3
View File
@@ -150,6 +150,8 @@ static void detectQualcomm(FFCPUResult* cpu)
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;
@@ -192,6 +194,7 @@ static void detectMediaTek(FFCPUResult* cpu)
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;
+8 -3
View File
@@ -102,12 +102,16 @@ const char* detectThermalTemp(double* result)
if (pCounterData->dwDataSize == sizeof(int32_t))
{
DWORD* pCounterIds = (DWORD*)(pMultiCounters + 1);
int32_t value = *(int32_t*)(pCounterData + 1);
if (value == 0)
return "Temperature data is zero";
switch (pCounterIds[iCounter]) {
case 0: // Temperature
*result = *(int32_t*)(pCounterData + 1) - 273;
*result = value - 273;
break;
case 3: // High Precision Temperature
*result = *(int32_t*)(pCounterData + 1) / 10.0 - 273;
*result = value / 10.0 - 273;
break;
}
}
@@ -238,7 +242,8 @@ static const char* detectByRegistry(FFCPUResult* cpu)
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed";
ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL);
ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL);
if (ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL))
ffStrbufTrimRightSpace(&cpu->vendor);
if (cpu->coresLogical == 0)
{
-25
View File
@@ -1,30 +1,5 @@
#include "disk.h"
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint)
{
#ifdef _WIN32
const char separator = ';';
#else
const char separator = ':';
#endif
uint32_t mountpointLength = (uint32_t) strlen(mountpoint);
uint32_t startIndex = 0;
while(startIndex < folders->length)
{
uint32_t colonIndex = ffStrbufNextIndexC(folders, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == mountpointLength && memcmp(folders->chars + startIndex, mountpoint, mountpointLength) == 0)
return true;
startIndex = colonIndex + 1;
}
return false;
}
static int compareDisks(const FFDisk* disk1, const FFDisk* disk2)
{
return ffStrbufComp(&disk1->mountpoint, &disk2->mountpoint);
+6 -1
View File
@@ -3,6 +3,12 @@
#include "fastfetch.h"
#include "modules/disk/option.h"
#ifdef _WIN32
#define FF_DISK_FOLDER_SEPARATOR ';'
#else
#define FF_DISK_FOLDER_SEPARATOR ':'
#endif
typedef struct FFDisk
{
FFstrbuf mountFrom;
@@ -29,4 +35,3 @@ typedef struct FFDisk
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint);
+1 -1
View File
@@ -145,7 +145,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if(__builtin_expect(options->folders.length > 0, 0))
{
if(!ffDiskMatchMountpoint(&options->folders, fs->f_mntonname))
if(!ffStrbufSeparatedContainS(&options->folders, fs->f_mntonname, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs"))
+1 -1
View File
@@ -23,7 +23,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(&options->folders, path.Path()))
if (!ffStrbufSeparatedContainS(&options->folders, path.Path(), FF_DISK_FOLDER_SEPARATOR))
continue;
}
+7 -3
View File
@@ -10,6 +10,10 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#ifdef STATX_BTIME
#include <sys/syscall.h>
#endif
#ifdef __USE_LARGEFILE64
#define stat stat64
#define statvfs statvfs64
@@ -263,9 +267,9 @@ static void detectStats(FFDisk* disk)
}
disk->createTime = 0;
#ifdef FF_HAVE_STATX
#ifdef SYS_statx
struct statx stx;
if (statx(0, disk->mountpoint.chars, 0, STATX_BTIME, &stx) == 0 && (stx.stx_mask & STATX_BTIME))
if (syscall(SYS_statx, 0, disk->mountpoint.chars, 0, STATX_BTIME, &stx) == 0 && (stx.stx_mask & STATX_BTIME) && stx.stx_btime.tv_sec > 685065600 /*birth of Linux*/)
disk->createTime = (uint64_t)((stx.stx_btime.tv_sec * 1000) + (stx.stx_btime.tv_nsec / 1000000));
#endif
@@ -287,7 +291,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if (__builtin_expect(options->folders.length > 0, false))
{
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
if (!ffStrbufSeparatedContainS(&options->folders, device->mnt_dir, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(!isPhysicalDevice(device))
+1 -1
View File
@@ -113,7 +113,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
{
if (__builtin_expect(options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(&options->folders, device.mnt_mountp))
if (!ffStrbufSeparatedContainS(&options->folders, device.mnt_mountp, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(!isPhysicalDevice(&device))
+1 -1
View File
@@ -47,7 +47,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
if (__builtin_expect((long) options->folders.length, 0))
{
if (!ffDiskMatchMountpoint(&options->folders, buffer.chars))
if (!ffStrbufSeparatedContain(&options->folders, &buffer, FF_DISK_FOLDER_SEPARATOR))
continue;
}
else if(driveType == DRIVE_NO_ROOT_DIR)
+13
View File
@@ -3,6 +3,19 @@
#include "fastfetch.h"
#include "modules/localip/option.h"
#ifndef IN6_IS_ADDR_GLOBAL
#define IN6_IS_ADDR_GLOBAL(a) \
((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000))
#endif
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) \
((((const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl(0xfc000000))
#endif
#ifndef IN6_IS_ADDR_LINKLOCAL
#define IN6_IS_ADDR_LINKLOCAL(a) \
((((const uint32_t *) (a))[0] & htonl(0xffc00000)) == htonl(0xfe800000))
#endif
typedef struct FFLocalIpResult
{
FFstrbuf name;
+62 -58
View File
@@ -111,47 +111,32 @@ static const FFLocalIpNIFlag niFlagOptions[] = {
{},
};
typedef enum __attribute__((__packed__)) FFIPv6Type
{
FF_IPV6_Other,
FF_IPV6_GUA = 0b0001,
FF_IPV6_GUA_SECONDARY = 0b0101,
FF_IPV6_ULA = 0b0010,
FF_IPV6_ULA_SECONDARY = 0b0110,
FF_IPV6_TYPE_MASK = 0b0011,
FF_IPV6_SECONDARY_FLAG = 0b1100,
FF_IPV6_PREFERRED = UINT8_MAX,
} FFIPv6Type;
static FFIPv6Type getIpType(struct ifaddrs* ifa)
static FFLocalIpIpv6Type getIpv6Type(struct ifaddrs* ifa)
{
struct sockaddr_in6* addr = (struct sockaddr_in6*) ifa->ifa_addr;
FF_DEBUG("Checking IPv6 type for interface %s", ifa->ifa_name);
#ifndef IN6_IS_ADDR_GLOBAL
#define IN6_IS_ADDR_GLOBAL(a) \
((((const uint32_t *) (a))[0] & htonl(0x70000000)) == htonl(0x20000000))
#endif
#ifndef IN6_IS_ADDR_UNIQUE_LOCAL
#define IN6_IS_ADDR_UNIQUE_LOCAL(a) \
((((const uint32_t *) (a))[0] & htonl(0xfe000000)) == htonl(0xfc000000))
#endif
FFIPv6Type result = FF_IPV6_Other;
FFLocalIpIpv6Type result = FF_LOCALIP_IPV6_TYPE_NONE;
if (IN6_IS_ADDR_GLOBAL(&addr->sin6_addr))
{
result = FF_IPV6_GUA;
result = FF_LOCALIP_IPV6_TYPE_GUA_BIT;
FF_DEBUG("Interface %s has Global Unicast Address", ifa->ifa_name);
}
else if (IN6_IS_ADDR_UNIQUE_LOCAL(&addr->sin6_addr))
{
result = FF_IPV6_ULA;
result = FF_LOCALIP_IPV6_TYPE_ULA_BIT;
FF_DEBUG("Interface %s has Unique Local Address", ifa->ifa_name);
}
else if (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))
{
result = FF_LOCALIP_IPV6_TYPE_LLA_BIT;
FF_DEBUG("Interface %s has Link-Local Address", ifa->ifa_name);
}
else
{
FF_DEBUG("Interface %s has other IPv6 address type", ifa->ifa_name);
return FF_IPV6_Other;
FF_DEBUG("Interface %s has unknown IPv6 address type", ifa->ifa_name);
return FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT;
}
#ifdef SIOCGIFAFLAG_IN6
@@ -178,13 +163,13 @@ static FFIPv6Type getIpType(struct ifaddrs* ifa)
#ifdef IN6_IFF_PREFER_SOURCE
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_PREFER_SOURCE)
return FF_IPV6_PREFERRED;
result |= FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT;
#endif
if (ifr6.ifr_ifru.ifru_flags6 & (IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY | IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED
#ifdef IN6_IFF_OPTIMISTIC
| IN6_IFF_OPTIMISTIC
#endif
)) result |= FF_IPV6_SECONDARY_FLAG;
)) result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
return result;
#elif __linux__
static FFlist addresses = {};
@@ -220,13 +205,13 @@ static FFIPv6Type getIpType(struct ifaddrs* ifa)
if (memcmp(&addr->sin6_addr, entry, sizeof(struct in6_addr)) == 0)
return result;
}
result |= FF_IPV6_SECONDARY_FLAG;
result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
return result;
#elif __sun
if (ifa->ifa_flags & IFF_PREFERRED)
return FF_IPV6_PREFERRED;
result |= FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT;
if (ifa->ifa_flags & (IFF_DEPRECATED | IFF_TEMPORARY | IFF_DUPLICATE))
result |= FF_IPV6_SECONDARY_FLAG;
result |= FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT;
return result;
#else
return result;
@@ -509,46 +494,65 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
}
}
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
if (options->ipv6Type == FF_LOCALIP_IPV6_TYPE_AUTO)
{
struct ifaddrs* selected = NULL;
struct ifaddrs* secondary = NULL;
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
{
FFIPv6Type type = getIpType(*pifa);
if (type == FF_IPV6_PREFERRED)
struct ifaddrs* selected = NULL;
struct ifaddrs* secondary = NULL;
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
{
selected = *pifa;
FF_DEBUG("Found preferred IPv6 address for interface %s", adapter->mac->ifa_name);
break;
FFLocalIpIpv6Type type = getIpv6Type(*pifa);
if (type & FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT)
{
selected = *pifa;
FF_DEBUG("Found preferred IPv6 address for interface %s", adapter->mac->ifa_name);
break;
}
else if ((type & FF_LOCALIP_IPV6_TYPE_GUA_BIT) && !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT) && !selected)
{
selected = *pifa;
FF_DEBUG("Found GUA IPv6 address for interface %s", adapter->mac->ifa_name);
}
else if ((type & FF_LOCALIP_IPV6_TYPE_ULA_BIT) && !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT) && !secondary)
{
secondary = *pifa;
FF_DEBUG("Found ULA IPv6 address for interface %s", adapter->mac->ifa_name);
}
}
else if (type == FF_IPV6_GUA && !selected)
if (!selected) selected = secondary;
if (selected)
appendIpv6(options, &item->ipv6, selected);
else if (adapter->ipv6.length > 0)
{
selected = *pifa;
FF_DEBUG("Found GUA IPv6 address for interface %s", adapter->mac->ifa_name);
}
else if (type == FF_IPV6_ULA && !secondary)
{
secondary = *pifa;
FF_DEBUG("Found ULA IPv6 address for interface %s", adapter->mac->ifa_name);
appendIpv6(options, &item->ipv6, *FF_LIST_GET(struct ifaddrs*, adapter->ipv6, 0));
FF_DEBUG("Using first IPv6 address for interface %s", adapter->mac->ifa_name);
}
}
if (!selected) selected = secondary;
if (selected)
appendIpv6(options, &item->ipv6, selected);
else if (adapter->ipv6.length > 0)
else
{
appendIpv6(options, &item->ipv6, *FF_LIST_GET(struct ifaddrs*, adapter->ipv6, 0));
FF_DEBUG("Using first IPv6 address for interface %s", adapter->mac->ifa_name);
FF_DEBUG("Adding all IPv6 addresses for interface %s", adapter->mac->ifa_name);
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
appendIpv6(options, &item->ipv6, *pifa);
}
}
else
{
FF_DEBUG("Adding all IPv6 addresses for interface %s", adapter->mac->ifa_name);
FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6)
appendIpv6(options, &item->ipv6, *pifa);
{
FFLocalIpIpv6Type type = getIpv6Type(*pifa);
if (type & options->ipv6Type)
{
if ((options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) || !(type & FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT))
{
appendIpv6(options, &item->ipv6, *pifa);
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
break;
}
}
}
}
}
mac:
+30 -6
View File
@@ -140,13 +140,24 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
for (IP_ADAPTER_UNICAST_ADDRESS* ifa = adapter->FirstUnicastAddress; ifa; ifa = ifa->Next)
{
FF_DEBUG("Processing unicast address: family=%d, DadState=%d",
ifa->Address.lpSockaddr->sa_family, ifa->DadState);
FF_DEBUG("Processing unicast address: prefix origin=%d, suffix origin=%d, family=%d, DadState=%d",
ifa->PrefixOrigin, ifa->SuffixOrigin, ifa->Address.lpSockaddr->sa_family, ifa->DadState);
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT) && ifa->DadState != IpDadStatePreferred)
if (!(options->showType & FF_LOCALIP_TYPE_ALL_IPS_BIT))
{
FF_DEBUG("Skipping address (DadState=%d, not preferred)", ifa->DadState);
continue;
if (ifa->DadState != IpDadStatePreferred)
{
FF_DEBUG("Skipping address (not preferred)");
continue;
}
if (ifa->SuffixOrigin == IpSuffixOriginRandom)
{
FF_DEBUG("Skipping temporary address (random suffix)");
continue;
}
// MIB_UNICASTIPADDRESS_ROW::SkipAsSource
}
if (ifa->Address.lpSockaddr->sa_family == AF_INET)
@@ -192,6 +203,20 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
continue;
}
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
FFLocalIpIpv6Type ipv6Type = FF_LOCALIP_IPV6_TYPE_NONE;
if (IN6_IS_ADDR_GLOBAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_GUA_BIT;
else if (IN6_IS_ADDR_UNIQUE_LOCAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_ULA_BIT;
else if (IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr)) ipv6Type |= FF_LOCALIP_IPV6_TYPE_LLA_BIT;
else ipv6Type |= FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT;
if (!(options->ipv6Type & ipv6Type))
{
FF_DEBUG("Skipping IPv6 address (doesn't match requested type 0x%X)", options->ipv6Type);
continue;
}
bool isDefaultRoute = ((options->showType & FF_LOCALIP_TYPE_IPV6_BIT) && ffNetifGetDefaultRouteV6()->ifIndex == adapter->IfIndex);
if ((options->showType & FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT) && !isDefaultRoute)
{
@@ -199,7 +224,6 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results)
continue;
}
SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr;
char addressBuffer[INET6_ADDRSTRLEN + 6];
inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN);
+48 -52
View File
@@ -7,9 +7,6 @@
typedef struct WGLData
{
FFOpenGLResult* result;
const char* error;
FF_LIBRARY_SYMBOL(glGetString)
FF_LIBRARY_SYMBOL(wglMakeCurrent)
FF_LIBRARY_SYMBOL(wglCreateContext)
@@ -18,82 +15,77 @@ typedef struct WGLData
void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglGetString);
static const char* wglHandleContext(WGLData* wglData, HDC hdc, HGLRC context)
static const char* wglHandleContext(WGLData* wglData, FFOpenGLResult* result, HDC hdc, HGLRC context)
{
if(wglData->ffwglMakeCurrent(hdc, context) == FALSE)
return "wglMakeCurrent() failed";
ffOpenGLHandleResult(wglData->result, wglData->ffglGetString);
ffStrbufSetStatic(&wglData->result->library, "WGL 1.0");
ffOpenGLHandleResult(result, wglData->ffglGetString);
ffStrbufSetStatic(&result->library, "WGL 1.0");
if(wglData->ffwglMakeCurrent(NULL, NULL) == FALSE)
return "wglMakeCurrent(NULL, NULL) failed";
return NULL;
}
static const char* wglHandlePixelFormat(WGLData* wglData, HWND hWnd)
static const char* wglHandlePixelFormat(WGLData* wglData, FFOpenGLResult* result, HWND hWnd)
{
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(pfd),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
32, // Colordepth of the framebuffer.
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
24, // Number of bits for the depthbuffer
8, // Number of bits for the stencilbuffer
0, // Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE,
0,
0, 0, 0
};
HDC hdc = GetDC(hWnd);
if(SetPixelFormat(hdc, ChoosePixelFormat(hdc, &pfd), &pfd) == FALSE)
if(hdc == NULL)
return "GetDC() failed";
PIXELFORMATDESCRIPTOR pfd = {
.nSize = sizeof(PIXELFORMATDESCRIPTOR),
.nVersion = 1,
.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
.iPixelType = PFD_TYPE_RGBA,
.cColorBits = 32,
.cDepthBits = 24,
.iLayerType = PFD_MAIN_PLANE
};
int pixelFormat = ChoosePixelFormat(hdc, &pfd);
if(pixelFormat == 0)
{
ReleaseDC(hWnd, hdc);
return "ChoosePixelFormat() failed";
}
if(SetPixelFormat(hdc, pixelFormat, &pfd) == FALSE)
{
ReleaseDC(hWnd, hdc);
return "SetPixelFormat() failed";
}
HGLRC context = wglData->ffwglCreateContext(hdc);
if(context == NULL)
{
ReleaseDC(hWnd, hdc);
return "wglCreateContext() failed";
}
const char* error = wglHandleContext(wglData, hdc, context);
const char* error = wglHandleContext(wglData, result, hdc, context);
wglData->ffwglDeleteContext(context);
return error;
}
ReleaseDC(hWnd, hdc);
static LRESULT CALLBACK wglHandleWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_CREATE: {
WGLData* wglData = (WGLData*)((CREATESTRUCT*)lParam)->lpCreateParams;
wglData->error = wglHandlePixelFormat(wglData, hWnd);
PostQuitMessage(0);
return 0;
}
default:
return DefWindowProcW(hWnd, message, wParam, lParam);
}
return error;
}
static const char* wglDetectOpenGL(FFOpenGLResult* result)
{
FF_LIBRARY_LOAD(opengl32, "dlopen opengl32" FF_LIBRARY_EXTENSION " failed", "opengl32" FF_LIBRARY_EXTENSION, 1);
WGLData data = { .result = result };
WGLData data = {};
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglMakeCurrent);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglCreateContext);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, wglDeleteContext);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opengl32, data, glGetString);
MSG msg = {0};
HINSTANCE hInstance = GetModuleHandleW(NULL);
WNDCLASSW wc = {
.lpfnWndProc = wglHandleWndProc,
.hInstance = NULL,
.lpfnWndProc = DefWindowProcW,
.hInstance = hInstance,
.hbrBackground = (HBRUSH)COLOR_BACKGROUND,
.lpszClassName = L"ogl_version_check",
.style = CS_OWNDC,
@@ -101,12 +93,16 @@ static const char* wglDetectOpenGL(FFOpenGLResult* result)
if(!RegisterClassW(&wc))
return "RegisterClassW() failed";
HWND hWnd = CreateWindowW(wc.lpszClassName, L"ogl_version_check", 0, 0, 0, FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT, NULL, NULL, NULL, &data);
HWND hWnd = CreateWindowW(wc.lpszClassName, L"ogl_version_check", 0, 0, 0, FF_OPENGL_BUFFER_WIDTH, FF_OPENGL_BUFFER_HEIGHT, NULL, NULL, hInstance, NULL);
if(!hWnd)
return "CreateWindowW() failed";
while(GetMessageW(&msg, hWnd, 0, 0) > 0)
DispatchMessage(&msg);
const char* error = wglHandlePixelFormat(&data, result, hWnd);
return data.error;
DestroyWindow(hWnd);
UnregisterClassW(wc.lpszClassName, hInstance);
return error;
}
+4 -4
View File
@@ -61,10 +61,6 @@ FF_MAYBE_UNUSED static bool detectArmbianVersion(FFOSResult* result)
FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
{
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if(!ffStrSet(xdgConfigDirs))
return;
if (detectArmbianVersion(result))
return;
else if(ffStrbufStartsWithS(&result->prettyName, "Linux Lite "))
@@ -104,6 +100,10 @@ FF_MAYBE_UNUSED static void getUbuntuFlavour(FFOSResult* result)
return;
}
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if(!ffStrSet(xdgConfigDirs))
return;
if(ffStrContains(xdgConfigDirs, "kde") || ffStrContains(xdgConfigDirs, "plasma") || ffStrContains(xdgConfigDirs, "kubuntu"))
{
ffStrbufSetStatic(&result->name, "Kubuntu");
+58 -13
View File
@@ -3,6 +3,8 @@
#include "common/properties.h"
#include "common/processing.h"
#include "detection/terminalshell/terminalshell.h"
#include "util/debug.h"
#include "util/stringUtils.h"
static void detectAlacritty(FFTerminalFontResult* terminalFont)
{
@@ -48,29 +50,72 @@ static void detectAlacritty(FFTerminalFontResult* terminalFont)
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}
static void detectGhostty(FFTerminalFontResult* terminalFont)
static void detectGhostty(const FFstrbuf* exe, FFTerminalFontResult* terminalFont)
{
FF_DEBUG("detectGhostty: start");
FF_STRBUF_AUTO_DESTROY configPath = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontNameFallback = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();
FFpropquery fontQueryToml[] = {
{"font-family =", &fontName},
{"font-size =", &fontSize},
};
// Try ghostty +show-config first
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]){
exe->chars,
"+show-config",
NULL,
});
if(error != NULL)
{
FF_DEBUG("`ghostty +show-config` failed: %s", error);
return;
}
#if __APPLE__
ffParsePropFileConfigValues("com.mitchellh.ghostty/config", 2, fontQueryToml);
#endif
char* line = NULL;
size_t len = 0;
while (ffStrbufGetline(&line, &len, &buffer))
{
if (!fontName.length || !fontNameFallback.length)
{
if (ffStrStartsWith(line, "font-family = ")) {
FF_DEBUG("found %s", line);
ffStrbufSetNS(
!fontName.length ? &fontName : &fontNameFallback,
(uint32_t) (len - strlen("font-family = ")),
line + strlen("font-family = "));
continue;
}
}
if (!fontSize.length)
{
if (ffStrStartsWith(line, "font-size = ")) {
FF_DEBUG("found fallback %s", line);
ffStrbufSetNS(
&fontSize,
(uint32_t) (len - strlen("font-size = ")),
line + strlen("font-size = "));
continue;
}
}
}
ffParsePropFileConfigValues("ghostty/config", 2, fontQueryToml);
if(fontName.length == 0)
if (fontName.length == 0) {
ffStrbufAppendS(&fontName, "JetBrainsMono Nerd Font");
FF_DEBUG("using default family='%s'", fontName.chars);
}
if(fontSize.length == 0)
if (fontSize.length == 0) {
ffStrbufAppendS(&fontSize, "13");
FF_DEBUG("using default size='%s'", fontSize.chars);
}
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
if (fontNameFallback.length > 0) {
FF_DEBUG("applying fallback family='%s'", fontNameFallback.chars);
ffFontInitValues(&terminalFont->fallback, fontNameFallback.chars, NULL);
}
FF_DEBUG("result family='%s' size='%s'%s", fontName.chars, fontSize.chars, fontNameFallback.length ? " (with fallback)" : "");
FF_DEBUG("detectGhostty: end");
}
FF_MAYBE_UNUSED static void detectTTY(FFTerminalFontResult* terminalFont)
@@ -279,7 +324,7 @@ static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTermina
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "contour"))
detectContour(&terminal->exe, terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "ghostty"))
detectGhostty(terminalFont);
detectGhostty(&terminal->exe, terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "rio"))
detectRio(terminalFont);
+10 -240
View File
@@ -9,227 +9,11 @@ static inline double rssiToSignalQuality(int rssi)
return (double) (rssi >= -50 ? 100 : rssi <= -100 ? 0 : (rssi + 100) * 2);
}
static bool queryIpconfig(const char* ifName, FFstrbuf* result)
{
if (@available(macOS 15.6, *))
{
// ipconfig reports <redacted> too
return false;
}
@interface CWNetworkProfile()
@property(readonly, retain, nullable) NSArray<NSDictionary *> *bssidList;
@end
return ffProcessAppendStdOut(result, (char* const[]) {
"/usr/sbin/ipconfig",
"getsummary",
(char* const) ifName,
NULL
}) == NULL;
}
static bool getWifiInfoByIpconfig(FFstrbuf* ipconfig, const char* prefix, FFstrbuf* result)
{
// `ipconfig getsummary <interface>` returns a string like this:
// <dictionary> {
// BSSID : <redacted>
// IPv4 : <array> {
// ...
// }
// IPv6 : <array> {
// ...
// }
// InterfaceType : WiFi
// LinkStatusActive : TRUE
// NetworkID : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
// SSID : XXXXXX
// Security : WPA2_PSK
// }
const char* start = memmem(ipconfig->chars, ipconfig->length, prefix, strlen(prefix));
if (!start) return false;
start += strlen(prefix);
const char* end = strchr(start, '\n');
if (!end) return false;
ffStrbufSetNS(result, (uint32_t) (end - start), start);
return true;
}
static const char* detectByWdutil(FFlist* result)
{
FF_STRBUF_AUTO_DESTROY wdutil = ffStrbufCreate();
if (geteuid() != 0)
return "wdutil requires root privileges to run";
bool ok = ffProcessAppendStdOut(&wdutil, (char* const[]) {
"/usr/bin/wdutil",
"info",
NULL
}) == NULL;
if (!ok) return "Failed to run wdutil info command";
// ...
//
// WIFI
//
// <WIFI INFO>
//
// ...
{
// Remove unrelated lines
uint32_t start = ffStrbufFirstIndexS(&wdutil, "\nWIFI\n");
if (start >= wdutil.length)
return "wdutil info command did not return WIFI section (1)";
start += 6; // Skip "\nWIFI\n"
start = ffStrbufNextIndexC(&wdutil, start, '\n');
if (start >= wdutil.length)
return "wdutil info command did not return WIFI section (2)";
start++;
uint32_t end = ffStrbufNextIndexS(&wdutil, start, "\n——————————");
ffStrbufSubstr(&wdutil, start, end);
}
// `wdutil info <interface>` returns a string like this:
// MAC Address : xx:xx:xx:xx:xx:xx (hw=xx:xx:xx:xx:xx:xx)
// Interface Name : en0
// Power : On [On]
// Op Mode : STA
// SSID : XXX-XXX
// BSSID : xx:xx:xx:xx:xx:xx
// RSSI : -58 dBm
// CCA : 29 %
// Noise : -96 dBm
// Tx Rate : 173.0 Mbps
// Security : WPA2 Enterprise
// 802.1X Mode : User
// 802.1X Supplicant : Authenticated
// PHY Mode : 11ac
// MCS Index : 8
// Guard Interval : 400
// NSS : 2
// Channel : 5g165/20
// Country Code : CN
// Scan Cache Count : 28
// NetworkServiceID : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
// IPv4 Config Method : DHCP
// IPv4 Address : xx.xx.xx.xx
// IPv4 Router : xx.xx.xx.x
// IPv6 Config Method : Automatic
// IPv6 Address : xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
// IPv6 Router : None
// DNS : xxx.xxx.xxx.xxx
// : xxx.xxx.xxx.xxx
// BTC Mode : Off
// Desense :
// Chain Ack : []
// BTC Profile 2.4GHz : Disabled
// BTC Profile 5GHz : Disabled
// Sniffer Supported : YES
// Supports 6e : No
// Supported Channels : 2g1/20,2g2/20,2g3/20,2g4/20,2g5/20,2g6/20,2g7/20,2g8/20,2g9/20,2g10/20,2g11/20,2g12/20,2g13/20,5g36/20,5g40/20,5g44/20,5g48/20,5g52/20,5g56/20,5g60/20,5g64/20,5g149/20,5g153/20,5g157/20,5g161/20,5g165/20,5g36/40,5g40/40,5g44/40,5g48/40,5g52/40,5g56/40,5g60/40,5g64/40,5g149/40,5g153/40,5g157/40,5g161/40,5g36/80,5g40/80,5g44/80,5g48/80,5g52/80,5g56/80,5g60/80,5g64/80,5g149/80,5g153/80,5g157/80,5g161/80
FFWifiResult* item = (FFWifiResult*) ffListAdd(result);
ffStrbufInit(&item->inf.description);
ffStrbufInit(&item->inf.status);
ffStrbufInit(&item->conn.status);
ffStrbufInit(&item->conn.ssid);
ffStrbufInit(&item->conn.bssid);
ffStrbufInit(&item->conn.protocol);
ffStrbufInit(&item->conn.security);
item->conn.signalQuality = -DBL_MAX;
item->conn.rxRate = -DBL_MAX;
item->conn.txRate = -DBL_MAX;
item->conn.channel = 0;
item->conn.frequency = 0;
char* line = NULL;
size_t len = 0;
while (ffStrbufGetline(&line, &len, &wdutil))
{
const char* key = line + 4; // Skip " "
const char* value = key + strlen("MAC Address : ");
switch (key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3])
{
case 'Inte': // Interface Name
ffStrbufAppendS(&item->inf.description, value);
break;
case 'Powe': // Power
if (ffStrStartsWith(value, "On "))
ffStrbufSetStatic(&item->inf.status, "Power On");
else
ffStrbufSetStatic(&item->inf.status, "Power Off");
break;
case 'SSID': // SSID
ffStrbufAppendS(&item->conn.ssid, value);
break;
case 'BSSI': // BSSID
if (ffStrEquals(value, "None") && ffStrbufEqualS(&item->conn.ssid, "None"))
{
ffStrbufSetStatic(&item->conn.status, "Inactive");
ffStrbufClear(&item->conn.ssid); // None
return NULL;
}
ffStrbufSetStatic(&item->conn.status, "Active");
ffStrbufAppendS(&item->conn.bssid, value);
break;
case 'RSSI': // RSSI
item->conn.signalQuality = rssiToSignalQuality((int) strtol(value, NULL, 10));
break;
case 'Tx R': // Tx Rate
item->conn.txRate = strtod(value, NULL);
break;
case 'Secu': // Security
if (ffStrEquals(value, "None"))
ffStrbufSetStatic(&item->conn.security, "Insecure");
else
ffStrbufAppendS(&item->conn.security, value);
break;
case 'PHY ': // PHY Mode
if (ffStrEquals(value, "None"))
ffStrbufSetStatic(&item->conn.protocol, "none");
else if (ffStrEquals(value, "11a"))
ffStrbufSetStatic(&item->conn.protocol, "802.11a");
else if (ffStrEquals(value, "11b"))
ffStrbufSetStatic(&item->conn.protocol, "802.11b");
else if (ffStrEquals(value, "11g"))
ffStrbufSetStatic(&item->conn.protocol, "802.11g");
else if (ffStrEquals(value, "11n"))
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
else if (ffStrEquals(value, "11ac"))
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
else if (ffStrEquals(value, "11ax"))
ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
else if (ffStrEquals(value, "11be"))
ffStrbufSetStatic(&item->conn.protocol, "802.11be (Wi-Fi 7)");
else
ffStrbufAppendS(&item->conn.protocol, value);
break;
case 'Chan': // Channel
{
int band, channel;
if (sscanf(value, "%dg%d", &band, &channel) == 2)
{
item->conn.channel = (uint16_t) channel;
switch (band)
{
case 2: item->conn.frequency = 2400; break;
case 5: item->conn.frequency = 5400; break;
case 6: item->conn.frequency = 6400; break;
default: item->conn.frequency = 0; break;
}
}
break;
}
}
}
return NULL;
}
static const char* detectByCoreWlan(FFlist* result)
const char* ffDetectWifi(FFlist* result)
{
NSArray<CWInterface*>* interfaces = CWWiFiClient.sharedWiFiClient.interfaces;
if (!interfaces)
@@ -262,17 +46,19 @@ static const char* detectByCoreWlan(FFlist* result)
FF_STRBUF_AUTO_DESTROY ipconfig = ffStrbufCreate();
CWNetworkProfile* networkProfile = inf.configuration.networkProfiles.firstObject;
if (inf.ssid) // https://developer.apple.com/forums/thread/732431
ffStrbufAppendS(&item->conn.ssid, inf.ssid.UTF8String);
else if (ipconfig.length || (queryIpconfig(item->inf.description.chars, &ipconfig)))
getWifiInfoByIpconfig(&ipconfig, "\n SSID : ", &item->conn.ssid);
else if (networkProfile.ssid)
ffStrbufSetStatic(&item->conn.ssid, inf.configuration.networkProfiles.firstObject.ssid.UTF8String);
else
ffStrbufSetStatic(&item->conn.ssid, "<redacted>"); // https://developer.apple.com/forums/thread/732431
if (inf.bssid)
ffStrbufAppendS(&item->conn.bssid, inf.bssid.UTF8String);
else if (ipconfig.length || (queryIpconfig(item->inf.description.chars, &ipconfig)))
getWifiInfoByIpconfig(&ipconfig, "\n BSSID : ", &item->conn.bssid);
else if (networkProfile.bssidList)
ffStrbufSetStatic(&item->conn.bssid, [networkProfile.bssidList.firstObject[@"BSSID"] UTF8String]);
else
ffStrbufSetStatic(&item->conn.bssid, "<redacted>");
@@ -360,11 +146,6 @@ static const char* detectByCoreWlan(FFlist* result)
case 15 /*kCWSecurityOWETransition*/:
ffStrbufSetStatic(&item->conn.security, "OWE Transition");
break;
case kCWSecurityUnknown:
// Sonoma?
if (ipconfig.length || (queryIpconfig(item->inf.description.chars, &ipconfig)))
getWifiInfoByIpconfig(&ipconfig, "\n Security : ", &item->conn.security);
break;
default:
ffStrbufAppendF(&item->conn.security, "Unknown (%ld)", inf.security);
break;
@@ -382,14 +163,3 @@ static const char* detectByCoreWlan(FFlist* result)
return NULL;
}
const char* ffDetectWifi(FFlist* result)
{
if (@available(macOS 15.6, *))
{
if (detectByWdutil(result) == NULL)
return NULL;
}
return detectByCoreWlan(result);
}
+1 -1
View File
@@ -80,7 +80,7 @@ static int enumZpoolCallback(zpool_handle_t* zpool, void* param)
const char* ffDetectZpool(FFlist* result /* list of FFZpoolResult */)
{
FF_LIBRARY_LOAD(libzfs, "dlopen libzfs" FF_LIBRARY_EXTENSION " failed", "libzfs" FF_LIBRARY_EXTENSION, 4);
FF_LIBRARY_LOAD(libzfs, "dlopen libzfs" FF_LIBRARY_EXTENSION " failed", "libzfs" FF_LIBRARY_EXTENSION, 6);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libzfs, libzfs_init);
libzfs_handle_t* handle = fflibzfs_init();
+5
View File
@@ -749,7 +749,12 @@ static void run(FFdata* data)
if (useJsonConfig)
ffPrintJsonConfig(true /* prepare */, instance.state.resultDoc);
else
{
//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
ffPrepareCommandOption(data);
}
ffStart();
+16 -19
View File
@@ -1,19 +1,16 @@
$1-`$2
.$1o+`$2
`o$1oo/$2
`+o$1ooo:$2
`+oo$1oooo:$2
-+oo$1oooo+:$2
`/:-:+$1+oooo+:$2
`/++++/$1+++++++:$2
`/++++++$1++++++++:$2
`/+++oooo$1ooooooooo/`$2
./ooosssso$1++osssssso+`$2
.oossssso-`$1```/ossssss+`$2
-osssssso. $1 :ssssssso.$2
:osssssss/ $1 osssso+++.$2
/ossssssss/ $1 +ssssooo/-$2
`/ossssso+/:- $1 -:/+osssso+-$2
`+sso+:-` $1 `.-/+oso:$2
`++:. $1 `-/+/$2
.` $1 `/$2
$2 *+++++++#
$2#*******###$3 @
$2#*******###$3 @
$2#*******###$3 @ @
$2#*******##%$3 @
$3@@@@@@@@@ @ @ @
@ @ @ @ @
@ @ @ @ @
@ @ @ @
@ @ @ @ @
@ @ @@@@@@@@@
@$1#*******##%$3
@$1 ##########%$3
@$1 ##########%$3
@$1 ##########%
########%
-14
View File
@@ -1,14 +0,0 @@
*/
*,*,*(
,,,,,,,,,,,,,,,,,,,,,,,,
,*,*,*,*,*,*,*,*,*,*,*,*
,,,,,,,,,,,,,,,,,,,,,,,,
*,*,*,*,*,*,*,*,*,*,*,*,*,*,*
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,*
,*,*,*,*,*,*,*,*,*,*,*,*,*,*
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
(*,*,*,*,*,*,*,*,*,*,*,*,*,
,,,,,,,,,,,,,,,,
&*,*,*#@@*,*,*,
+20
View File
@@ -0,0 +1,20 @@
$1aooooo$2,
$1aooooo$2``
$1aooooo$2``
$3(((((( $1aooooo$2``$3((((((
$1oooo$3@@ @C@*;,./k@@ @@ @$1oooo$2
$1oooooo$3@@ @@@@@@@@ @@k$1oooooo$2``
$1oooooooo$3\@ @/@@ @@$1ooooooooo$2``
`````````$3'*@*/'$2````````````
$3@@@( $1aooooo$2`` $3@@@@
@@ @ $1aooooo$2`` $3@ @@
@@@ $1aooooo$2`` $3@@@,
@@ $1aooooo$2`` $3 @@
@ $1aooooo$2`` $3 (@
$1aooooo$2``
$1aooooo$2``
$1aooooo$2``
$1aooooo$2``
$1aooooo$2``
```````
`````
+11 -10
View File
@@ -3408,6 +3408,7 @@ static const FFlogo O[] = {
.colors = {
FF_COLOR_FG_MAGENTA,
FF_COLOR_FG_CYAN,
FF_COLOR_FG_LIGHT_BLUE,
},
},
// OmniOS
@@ -4615,16 +4616,6 @@ static const FFlogo S[] = {
FF_COLOR_FG_WHITE,
},
},
// Starry
{
.names = {"Starry"},
.lines = FASTFETCH_DATATEXT_LOGO_STARRY,
.colors = {
FF_COLOR_FG_GREEN,
},
.colorKeys = FF_COLOR_FG_GREEN,
.colorTitle = FF_COLOR_FG_DEFAULT,
},
// StockLinux
{
.names = {"Stock Linux"},
@@ -4778,6 +4769,16 @@ static const FFlogo T[] = {
FF_COLOR_FG_WHITE,
},
},
// TempleOS
{
.names = {"TempleOS"},
.lines = FASTFETCH_DATATEXT_LOGO_TEMPLEOS,
.colors = {
FF_COLOR_FG_YELLOW,
FF_COLOR_FG_RED,
FF_COLOR_FG_CYAN,
},
},
// TileOS
{
.names = {"TileOS"},
+31 -5
View File
@@ -203,10 +203,10 @@ bool ffPrintDisk(FFDiskOptions* options)
if(__builtin_expect(options->folders.length == 0, 1) && (disk->type & ~options->showTypes))
continue;
if (options->hideFolders.length && ffDiskMatchMountpoint(&options->hideFolders, disk->mountpoint.chars))
if (options->hideFolders.length && ffStrbufSeparatedContain(&options->hideFolders, &disk->mountpoint, FF_DISK_FOLDER_SEPARATOR))
continue;
if (options->hideFS.length && ffStrbufMatchSeparated(&disk->filesystem, &options->hideFS, ':'))
if (options->hideFS.length && ffStrbufSeparatedContain(&options->hideFS, &disk->filesystem, ':'))
continue;
printDisk(options, disk, ++index);
@@ -223,6 +223,32 @@ bool ffPrintDisk(FFDiskOptions* options)
return true;
}
static bool setSeparatedList(FFstrbuf* strbuf, yyjson_val* val, char separator)
{
if (yyjson_is_str(val))
{
ffStrbufSetJsonVal(strbuf, val);
return true;
}
if (yyjson_is_arr(val))
{
ffStrbufClear(strbuf);
yyjson_val *elem;
size_t eidx, emax;
yyjson_arr_foreach(val, eidx, emax, elem)
{
if (yyjson_is_str(elem))
{
if (strbuf->length > 0)
ffStrbufAppendC(strbuf, separator);
ffStrbufAppendJsonVal(strbuf, elem);
}
}
return true;
}
return false;
}
void ffParseDiskJsonObject(FFDiskOptions* options, yyjson_val* module)
{
yyjson_val *key, *val;
@@ -234,19 +260,19 @@ void ffParseDiskJsonObject(FFDiskOptions* options, yyjson_val* module)
if (unsafe_yyjson_equals_str(key, "folders"))
{
ffStrbufSetJsonVal(&options->folders, val);
setSeparatedList(&options->folders, val, FF_DISK_FOLDER_SEPARATOR);
continue;
}
if (unsafe_yyjson_equals_str(key, "hideFolders"))
{
ffStrbufSetJsonVal(&options->hideFolders, val);
setSeparatedList(&options->hideFolders, val, FF_DISK_FOLDER_SEPARATOR);
continue;
}
if (unsafe_yyjson_equals_str(key, "hideFS"))
{
ffStrbufSetJsonVal(&options->hideFS, val);
setSeparatedList(&options->hideFS, val, ':');
continue;
}
+76 -5
View File
@@ -68,15 +68,48 @@ bool ffPrintGamepad(FFGamepadOptions* options)
return false;
}
uint8_t index = 0;
FF_LIST_AUTO_DESTROY filtered = ffListCreate(sizeof(FFGamepadDevice*));
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
{
printDevice(options, device, result.length > 1 ? ++index : 0);
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
if(!ignored)
{
FFGamepadDevice** ptr = ffListAdd(&filtered);
*ptr = device;
}
}
return true;
bool ret = true;
if(!filtered.length)
{
ffPrintError(FF_GAMEPAD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "All devices are ignored");
ret = false;
}
else
{
uint8_t index = 0;
FF_LIST_FOR_EACH(FFGamepadDevice*, pdevice, filtered)
{
FFGamepadDevice* device = *pdevice;
printDevice(options, device, filtered.length > 1 ? ++index : 0);
}
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
{
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
}
}
return ret;
}
void ffParseGamepadJsonObject(FFGamepadOptions* options, yyjson_val* module)
@@ -88,6 +121,21 @@ void ffParseGamepadJsonObject(FFGamepadOptions* options, yyjson_val* module)
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
continue;
if (unsafe_yyjson_equals_str(key, "ignores"))
{
yyjson_val *elem;
size_t eidx, emax;
yyjson_arr_foreach(val, eidx, emax, elem)
{
if (yyjson_is_str(elem))
{
FFstrbuf* strbuf = ffListAdd(&options->ignores);
ffStrbufInitJsonVal(strbuf, elem);
}
}
continue;
}
if (ffPercentParseJsonObject(key, val, &options->percent))
continue;
@@ -99,6 +147,12 @@ void ffGenerateGamepadJsonConfig(FFGamepadOptions* options, yyjson_mut_doc* doc,
{
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
if (options->ignores.length > 0)
{
yyjson_mut_val* ignores = yyjson_mut_obj_add_arr(doc, module, "ignores");
FF_LIST_FOR_EACH(FFstrbuf, strbuf, options->ignores)
yyjson_mut_arr_append(ignores, yyjson_mut_strncpy(doc, strbuf->chars, strbuf->length));
}
ffPercentGenerateJsonConfig(doc, module, options->percent);
}
@@ -120,6 +174,17 @@ bool ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjs
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
yyjson_mut_obj_add_bool(doc, obj, "ignored", ignored);
}
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
@@ -134,12 +199,18 @@ bool ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjs
void ffInitGamepadOptions(FFGamepadOptions* options)
{
ffOptionInitModuleArg(&options->moduleArgs, "󰺵");
ffListInit(&options->ignores, sizeof(FFstrbuf));
options->percent = (FFPercentageModuleConfig) { 50, 20, 0 };
}
void ffDestroyGamepadOptions(FFGamepadOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
FF_LIST_FOR_EACH(FFstrbuf, str, options->ignores)
ffStrbufDestroy(str);
ffListDestroy(&options->ignores);
}
FFModuleBaseInfo ffGamepadModuleInfo = {
+2
View File
@@ -1,11 +1,13 @@
#pragma once
#include "common/option.h"
#include "util/FFlist.h"
typedef struct FFGamepadOptions
{
FFModuleArgs moduleArgs;
FFlist ignores; // List of FFstrbuf
FFPercentageModuleConfig percent;
} FFGamepadOptions;
+73 -5
View File
@@ -39,15 +39,44 @@ bool ffPrintKeyboard(FFKeyboardOptions* options)
return false;
}
uint8_t index = 0;
FF_LIST_AUTO_DESTROY filtered = ffListCreate(sizeof(FFKeyboardDevice*));
FF_LIST_FOR_EACH(FFKeyboardDevice, device, result)
{
printDevice(options, device, result.length > 1 ? ++index : 0);
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
if(!ignored)
{
FFKeyboardDevice** ptr = ffListAdd(&filtered);
*ptr = device;
}
}
return true;
bool ret = true;
if(!filtered.length)
{
ffPrintError(FF_KEYBOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "All devices are ignored");
ret = false;
}
else
{
uint8_t index = 0;
FF_LIST_FOR_EACH(FFKeyboardDevice*, pdevice, filtered)
{
FFKeyboardDevice* device = *pdevice;
printDevice(options, device, filtered.length > 1 ? ++index : 0);
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
}
}
return ret;
}
void ffParseKeyboardJsonObject(FFKeyboardOptions* options, yyjson_val* module)
@@ -59,6 +88,21 @@ void ffParseKeyboardJsonObject(FFKeyboardOptions* options, yyjson_val* module)
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
continue;
if (unsafe_yyjson_equals_str(key, "ignores"))
{
yyjson_val *elem;
size_t eidx, emax;
yyjson_arr_foreach(val, eidx, emax, elem)
{
if (yyjson_is_str(elem))
{
FFstrbuf* strbuf = ffListAdd(&options->ignores);
ffStrbufInitJsonVal(strbuf, elem);
}
}
continue;
}
ffPrintError(FF_KEYBOARD_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -66,6 +110,13 @@ void ffParseKeyboardJsonObject(FFKeyboardOptions* options, yyjson_val* module)
void ffGenerateKeyboardJsonConfig(FFKeyboardOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
if (options->ignores.length > 0)
{
yyjson_mut_val* ignores = yyjson_mut_obj_add_arr(doc, module, "ignores");
FF_LIST_FOR_EACH(FFstrbuf, strbuf, options->ignores)
yyjson_mut_arr_append(ignores, yyjson_mut_strncpy(doc, strbuf->chars, strbuf->length));
}
}
bool ffGenerateKeyboardJsonResult(FF_MAYBE_UNUSED FFKeyboardOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -86,6 +137,17 @@ bool ffGenerateKeyboardJsonResult(FF_MAYBE_UNUSED FFKeyboardOptions* options, yy
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
yyjson_mut_obj_add_bool(doc, obj, "ignored", ignored);
}
FF_LIST_FOR_EACH(FFKeyboardDevice, device, result)
@@ -100,11 +162,17 @@ bool ffGenerateKeyboardJsonResult(FF_MAYBE_UNUSED FFKeyboardOptions* options, yy
void ffInitKeyboardOptions(FFKeyboardOptions* options)
{
ffOptionInitModuleArg(&options->moduleArgs, "");
ffListInit(&options->ignores, sizeof(FFstrbuf));
}
void ffDestroyKeyboardOptions(FFKeyboardOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
FF_LIST_FOR_EACH(FFstrbuf, str, options->ignores)
ffStrbufDestroy(str);
ffListDestroy(&options->ignores);
}
FFModuleBaseInfo ffKeyboardModuleInfo = {
+3
View File
@@ -1,10 +1,13 @@
#pragma once
#include "common/option.h"
#include "util/FFlist.h"
typedef struct FFKeyboardOptions
{
FFModuleArgs moduleArgs;
FFlist ignores; // List of FFstrbuf
} FFKeyboardOptions;
static_assert(sizeof(FFKeyboardOptions) <= FF_OPTION_MAX_SIZE, "FFKeyboardOptions size exceeds maximum allowed size");
+43 -5
View File
@@ -198,10 +198,33 @@ void ffParseLocalIpJsonObject(FFLocalIpOptions* options, yyjson_val* module)
if (unsafe_yyjson_equals_str(key, "showIpv6"))
{
if (yyjson_get_bool(val))
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
else
options->showType &= ~FF_LOCALIP_TYPE_IPV6_BIT;
if (yyjson_is_bool(val))
{
options->ipv6Type = FF_LOCALIP_IPV6_TYPE_AUTO;
if (unsafe_yyjson_get_bool(val))
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
else
options->showType &= ~FF_LOCALIP_TYPE_IPV6_BIT;
}
else if (yyjson_is_str(val))
{
int value;
const char* error = ffJsonConfigParseEnum(val, &value, (FFKeyValuePair[]) {
{ "auto", FF_LOCALIP_IPV6_TYPE_AUTO },
{ "gua", FF_LOCALIP_IPV6_TYPE_GUA_BIT },
{ "ula", FF_LOCALIP_IPV6_TYPE_ULA_BIT },
{ "lla", FF_LOCALIP_IPV6_TYPE_LLA_BIT },
{ "unknown", FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT },
{},
});
if (error)
ffPrintError(FF_LOCALIP_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Invalid %s value: %s", unsafe_yyjson_get_str(key), error);
else
{
options->showType |= FF_LOCALIP_TYPE_IPV6_BIT;
options->ipv6Type = (FFLocalIpIpv6Type) value;
}
}
continue;
}
@@ -302,7 +325,21 @@ void ffGenerateLocalIpJsonConfig(FFLocalIpOptions* options, yyjson_mut_doc* doc,
yyjson_mut_obj_add_bool(doc, module, "showIpv4", !!(options->showType & FF_LOCALIP_TYPE_IPV4_BIT));
yyjson_mut_obj_add_bool(doc, module, "showIpv6", !!(options->showType & FF_LOCALIP_TYPE_IPV6_BIT));
if (options->ipv6Type == FF_LOCALIP_IPV6_TYPE_AUTO)
yyjson_mut_obj_add_bool(doc, module, "showIpv6", !!(options->showType & FF_LOCALIP_TYPE_IPV6_BIT));
else
{
const char* str = NULL;
switch (options->ipv6Type)
{
case FF_LOCALIP_IPV6_TYPE_GUA_BIT: str = "gua"; break;
case FF_LOCALIP_IPV6_TYPE_ULA_BIT: str = "ula"; break;
case FF_LOCALIP_IPV6_TYPE_LLA_BIT: str = "lla"; break;
case FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT: str = "unknown"; break;
default: str = "auto"; break;
}
yyjson_mut_obj_add_str(doc, module, "showIpv6", str);
}
yyjson_mut_obj_add_bool(doc, module, "showMac", !!(options->showType & FF_LOCALIP_TYPE_MAC_BIT));
@@ -385,6 +422,7 @@ void ffInitLocalIpOptions(FFLocalIpOptions* options)
| FF_LOCALIP_TYPE_DEFAULT_ROUTE_ONLY_BIT
#endif
;
options->ipv6Type = FF_LOCALIP_IPV6_TYPE_AUTO;
ffStrbufInit(&options->namePrefix);
}
+15
View File
@@ -21,11 +21,26 @@ typedef enum __attribute__((__packed__)) FFLocalIpType
} FFLocalIpType;
static_assert(sizeof(FFLocalIpType) == sizeof(uint16_t), "");
typedef enum __attribute__((__packed__)) FFLocalIpIpv6Type
{
FF_LOCALIP_IPV6_TYPE_NONE = 0b00000000,
FF_LOCALIP_IPV6_TYPE_GUA_BIT = 0b00000001,
FF_LOCALIP_IPV6_TYPE_ULA_BIT = 0b00000010,
FF_LOCALIP_IPV6_TYPE_LLA_BIT = 0b00000100,
FF_LOCALIP_IPV6_TYPE_UNKNOWN_BIT = 0b00001000, // IPv4-mapped, loopback, etc.
FF_LOCALIP_IPV6_TYPE_SECONDARY_BIT = 0b01000000, // Temporary, duplicated, etc.
FF_LOCALIP_IPV6_TYPE_PREFERRED_BIT = 0b10000000, // PREFER_SOURCE (manually set)
FF_LOCALIP_IPV6_TYPE_TYPE_MASK = 0b00011111,
FF_LOCALIP_IPV6_TYPE_AUTO = 0b11111111, // Used for detect option
} FFLocalIpIpv6Type;
static_assert(sizeof(FFLocalIpIpv6Type) == sizeof(uint8_t), "");
typedef struct FFLocalIpOptions
{
FFModuleArgs moduleArgs;
FFLocalIpType showType;
FFLocalIpIpv6Type ipv6Type;
FFstrbuf namePrefix;
} FFLocalIpOptions;
+75 -3
View File
@@ -39,15 +39,48 @@ bool ffPrintMouse(FFMouseOptions* options)
return false;
}
uint8_t index = 0;
FF_LIST_AUTO_DESTROY filtered = ffListCreate(sizeof(FFMouseDevice*));
FF_LIST_FOR_EACH(FFMouseDevice, device, result)
{
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
if(!ignored)
{
FFMouseDevice** ptr = ffListAdd(&filtered);
*ptr = device;
}
}
bool ret = true;
if(!filtered.length)
{
ffPrintError(FF_MOUSE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "All devices are ignored");
ret = false;
}
else
{
uint8_t index = 0;
FF_LIST_FOR_EACH(FFMouseDevice*, pdevice, filtered)
{
FFMouseDevice* device = *pdevice;
printDevice(options, device, filtered.length > 1 ? ++index : 0);
}
}
FF_LIST_FOR_EACH(FFMouseDevice, device, result)
{
printDevice(options, device, result.length > 1 ? ++index : 0);
ffStrbufDestroy(&device->serial);
ffStrbufDestroy(&device->name);
}
return true;
return ret;
}
void ffParseMouseJsonObject(FFMouseOptions* options, yyjson_val* module)
@@ -59,6 +92,21 @@ void ffParseMouseJsonObject(FFMouseOptions* options, yyjson_val* module)
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
continue;
if (unsafe_yyjson_equals_str(key, "ignores"))
{
yyjson_val *elem;
size_t eidx, emax;
yyjson_arr_foreach(val, eidx, emax, elem)
{
if (yyjson_is_str(elem))
{
FFstrbuf* strbuf = ffListAdd(&options->ignores);
ffStrbufInitJsonVal(strbuf, elem);
}
}
continue;
}
ffPrintError(FF_MOUSE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
@@ -66,6 +114,13 @@ void ffParseMouseJsonObject(FFMouseOptions* options, yyjson_val* module)
void ffGenerateMouseJsonConfig(FFMouseOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
if (options->ignores.length > 0)
{
yyjson_mut_val* ignores = yyjson_mut_obj_add_arr(doc, module, "ignores");
FF_LIST_FOR_EACH(FFstrbuf, strbuf, options->ignores)
yyjson_mut_arr_append(ignores, yyjson_mut_strncpy(doc, strbuf->chars, strbuf->length));
}
}
bool ffGenerateMouseJsonResult(FF_MAYBE_UNUSED FFMouseOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -86,6 +141,17 @@ bool ffGenerateMouseJsonResult(FF_MAYBE_UNUSED FFMouseOptions* options, yyjson_m
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &device->name);
bool ignored = false;
FF_LIST_FOR_EACH(FFstrbuf, ignore, options->ignores)
{
if(ffStrbufStartsWithIgnCase(&device->name, ignore))
{
ignored = true;
break;
}
}
yyjson_mut_obj_add_bool(doc, obj, "ignored", ignored);
}
FF_LIST_FOR_EACH(FFMouseDevice, device, result)
@@ -100,11 +166,17 @@ bool ffGenerateMouseJsonResult(FF_MAYBE_UNUSED FFMouseOptions* options, yyjson_m
void ffInitMouseOptions(FFMouseOptions* options)
{
ffOptionInitModuleArg(&options->moduleArgs, "󰍽");
ffListInit(&options->ignores, sizeof(FFstrbuf));
}
void ffDestroyMouseOptions(FFMouseOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
FF_LIST_FOR_EACH(FFstrbuf, str, options->ignores)
ffStrbufDestroy(str);
ffListDestroy(&options->ignores);
}
FFModuleBaseInfo ffMouseModuleInfo = {
+3
View File
@@ -1,10 +1,13 @@
#pragma once
#include "common/option.h"
#include "util/FFlist.h"
typedef struct FFMouseOptions
{
FFModuleArgs moduleArgs;
FFlist ignores; // List of FFstrbuf
} FFMouseOptions;
static_assert(sizeof(FFMouseOptions) <= FF_OPTION_MAX_SIZE, "FFMouseOptions size exceeds maximum allowed size");
+1 -1
View File
@@ -6,7 +6,7 @@ typedef struct FFSeparatorOptions
{
FFstrbuf string;
FFstrbuf outputColor;
uint32_t length;
uint32_t times;
} FFSeparatorOptions;
static_assert(sizeof(FFSeparatorOptions) <= FF_OPTION_MAX_SIZE, "FFSeparatorOptions size exceeds maximum allowed size");
+63 -41
View File
@@ -9,27 +9,52 @@
#include <locale.h>
static inline uint32_t max(uint32_t a, uint32_t b)
#if __SIZEOF_WCHAR_T__ == 4
static inline size_t mbrtoc32(uint32_t* restrict pc32, const char* restrict s, size_t n, mbstate_t* restrict ps)
{
return mbrtowc((wchar_t*) pc32, s, n, ps);
}
#else
#include <uchar.h>
#endif
static uint8_t getMbrWidth(const char* mbstr, uint32_t length, const char** next, mbstate_t* state)
{
return a > b ? a : b;
if (__builtin_expect((uint8_t) *mbstr < 0x80, true)) // ASCII fast path
{
if (next) *next = mbstr + 1;
return 1;
}
uint32_t c32;
uint32_t len = (uint32_t) mbrtoc32(&c32, mbstr, length, state);
if (len >= (uint32_t) -3)
{
// Invalid or incomplete multibyte sequence
if (next) *next = mbstr + 1;
return 1;
}
if (next) *next = mbstr + len;
int width = mk_wcwidth(c32);
return width < 0 ? 0 : (uint8_t) width;
}
static inline uint32_t getWcsWidth(const FFstrbuf* mbstr, wchar_t* wstr, mbstate_t* state)
static uint32_t getWcsWidth(const FFstrbuf* mbstr)
{
int result = 1;
for (uint32_t i = 0; i < mbstr->length; i++)
{
if (!isascii(mbstr->chars[i]))
{
result = 0;
break;
}
}
if (__builtin_expect(result, 1)) return mbstr->length;
mbstate_t state = {};
uint32_t remainLength = mbstr->length;
uint32_t result = 0;
const char* ptr = mbstr->chars;
while (remainLength > 0 && *ptr != '\0')
{
const char* lastPtr = NULL;
result += getMbrWidth(ptr, remainLength, &lastPtr, &state);
remainLength -= (uint32_t)(lastPtr - ptr);
ptr = lastPtr;
}
const char* str = mbstr->chars;
uint32_t wstrLength = (uint32_t) mbsrtowcs(wstr, &str, mbstr->length, state);
result = mk_wcswidth(wstr, wstrLength);
return result > 0 ? (uint32_t) result : mbstr->length;
}
@@ -40,13 +65,13 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
if(options->outputColor.length && !instance.config.display.pipe)
ffPrintColor(&options->outputColor);
if (options->length > 0)
if (options->times > 0)
{
if(__builtin_expect(options->string.length == 1, 1))
ffPrintCharTimes(options->string.chars[0], options->length);
ffPrintCharTimes(options->string.chars[0], options->times);
else
{
for (uint32_t i = 0; i < options->length; i++)
for (uint32_t i = 0; i < options->times; i++)
{
fputs(options->string.chars, stdout);
}
@@ -55,14 +80,10 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
else
{
setlocale(LC_CTYPE, "");
mbstate_t state = {};
const FFPlatform* platform = &instance.state.platform;
FF_AUTO_FREE wchar_t* wstr = malloc((max(
platform->userName.length, options->string.length) + 1) * sizeof(*wstr));
uint32_t titleLength = 1 // @
+ getWcsWidth(&platform->userName, wstr, &state) // user name
+ getWcsWidth(&platform->userName) // user name
+ (instance.state.titleFqdn ? platform->hostName.length : ffStrbufFirstIndexC(&platform->hostName, '.')); // host name
if(__builtin_expect(options->string.length == 1, 1))
@@ -71,7 +92,7 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
}
else
{
uint32_t wcsLength = getWcsWidth(&options->string, wstr, &state);
uint32_t wcsLength = getWcsWidth(&options->string);
int remaining = (int) titleLength;
//Write the whole separator as often as it fits fully into titleLength
@@ -84,24 +105,19 @@ bool ffPrintSeparator(FFSeparatorOptions* options)
if (wcsLength != options->string.length)
{
// Unicode chars
for(int i = 0; remaining > 0; ++i)
const char* ptr = options->string.chars;
mbstate_t state = {};
const char* next = NULL;
while (remaining > 0 && *ptr != '\0')
{
#ifdef __linux__
// https://stackoverflow.com/questions/75126743/i-have-difficulties-with-putwchar-in-c#answer-75137784
char wch[16] = "";
uint32_t wchLength = (uint32_t) wcrtomb(wch, wstr[i], &state);
fwrite(wch, wchLength, 1, stdout);
#else
putwchar(wstr[i]);
#endif
int width = mk_wcwidth(wstr[i]);
remaining -= width < 0 ? 0 : width;
remaining -= (int) getMbrWidth(ptr, (uint32_t)(options->string.length - (ptr - options->string.chars)), &next, &state);
ptr = next;
}
fwrite(options->string.chars, (size_t) (ptr - options->string.chars), 1, stdout);
}
else
{
for(int i = 0; i < remaining; i++)
putchar(options->string.chars[i]);
fwrite(options->string.chars, (size_t) remaining, 1, stdout);
}
}
}
@@ -136,9 +152,15 @@ void ffParseSeparatorJsonObject(FFSeparatorOptions* options, yyjson_val* module)
continue;
}
if (unsafe_yyjson_equals_str(key, "times"))
{
options->times = (uint32_t) yyjson_get_uint(val);
continue;
}
if (unsafe_yyjson_equals_str(key, "length"))
{
options->length = (uint32_t) yyjson_get_uint(val);
ffPrintError(FF_SEPARATOR_MODULE_NAME, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "The option length has been renamed to times.");
continue;
}
@@ -150,14 +172,14 @@ void ffGenerateSeparatorJsonConfig(FFSeparatorOptions* options, yyjson_mut_doc*
{
yyjson_mut_obj_add_strbuf(doc, module, "string", &options->string);
yyjson_mut_obj_add_strbuf(doc, module, "outputColor", &options->outputColor);
yyjson_mut_obj_add_uint(doc, module, "length", options->length);
yyjson_mut_obj_add_uint(doc, module, "times", options->times);
}
void ffInitSeparatorOptions(FFSeparatorOptions* options)
{
ffStrbufInitStatic(&options->string, "-");
ffStrbufInit(&options->outputColor);
options->length = 0;
options->times = 0;
}
void ffDestroySeparatorOptions(FFSeparatorOptions* options)
+65 -1
View File
@@ -730,7 +730,7 @@ bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf)
return changed;
}
/// @brief Check if a separated string contains a substring.
/// @brief Check if a separated string (comp) contains a substring (strbuf).
/// @param strbuf The substring to check.
/// @param compLength The length of the separated string to check.
/// @param comp The separated string to check.
@@ -759,6 +759,31 @@ bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const
return false;
}
/// @brief Case insensitive version of ffStrbufMatchSeparatedNS.
bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
{
if (strbuf->length == 0)
return true;
if (compLength == 0)
return false;
for (const char* p = comp; p < comp + compLength;)
{
const char* colon = memchr(p, separator, compLength);
if (colon == NULL)
return strcasecmp(strbuf->chars, p) == 0;
uint32_t substrLength = (uint32_t) (colon - p);
if (strbuf->length == substrLength && strncasecmp(strbuf->chars, p, substrLength) == 0)
return true;
p = colon + 1;
}
return false;
}
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint)
{
if (codepoint <= 0x7F) {
@@ -790,3 +815,42 @@ int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint)
ffStrbufAppendS(strbuf, ""); // U+FFFD REPLACEMENT CHARACTER
return 1;
}
/// @brief Check if a separated string (strbuf) contains a substring (comp).
/// @param strbuf The separated to check.
/// @param compLength The length of the separated string to check.
/// @param comp The substring to check.
/// @param separator The separator character.
bool ffStrbufSeparatedContainNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
{
uint32_t startIndex = 0;
while(startIndex < strbuf->length)
{
uint32_t colonIndex = ffStrbufNextIndexC(strbuf, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == compLength && memcmp(strbuf->chars + startIndex, comp, compLength) == 0)
return true;
startIndex = colonIndex + 1;
}
return false;
}
bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
{
uint32_t startIndex = 0;
while(startIndex < strbuf->length)
{
uint32_t colonIndex = ffStrbufNextIndexC(strbuf, startIndex, separator);
uint32_t folderLength = colonIndex - startIndex;
if (folderLength == compLength && strncasecmp(strbuf->chars + startIndex, comp, compLength) == 0)
return true;
startIndex = colonIndex + 1;
}
return false;
}
+33
View File
@@ -100,6 +100,9 @@ bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer);
void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer);
bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf);
bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufSeparatedContainNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint);
@@ -566,4 +569,34 @@ static inline bool ffStrbufMatchSeparated(const FFstrbuf* strbuf, const FFstrbuf
return ffStrbufMatchSeparatedNS(strbuf, comp->length, comp->chars, separator);
}
static inline bool ffStrbufMatchSeparatedIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator)
{
return ffStrbufMatchSeparatedIgnCaseNS(strbuf, (uint32_t) strlen(comp), comp, separator);
}
static inline bool ffStrbufMatchSeparatedIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
{
return ffStrbufMatchSeparatedIgnCaseNS(strbuf, comp->length, comp->chars, separator);
}
static inline bool ffStrbufSeparatedContainS(const FFstrbuf* strbuf, const char* comp, char separator)
{
return ffStrbufSeparatedContainNS(strbuf, (uint32_t) strlen(comp), comp, separator);
}
static inline bool ffStrbufSeparatedContain(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
{
return ffStrbufSeparatedContainNS(strbuf, comp->length, comp->chars, separator);
}
static inline bool ffStrbufSeparatedContainIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator)
{
return ffStrbufSeparatedContainIgnCaseNS(strbuf, (uint32_t) strlen(comp), comp, separator);
}
static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
{
return ffStrbufSeparatedContainIgnCaseNS(strbuf, comp->length, comp->chars, separator);
}
#define FF_STRBUF_AUTO_DESTROY FFstrbuf __attribute__((__cleanup__(ffStrbufDestroy)))
+32
View File
@@ -0,0 +1,32 @@
#include "wcwidth.h"
#include "3rdparty/widecharwidth/widechar_width_c.h"
int mk_wcwidth(uint32_t wc)
{
// // We render U+1F6E1 (🛡) with a width of 2,
// // but widechar_width says it has a width of 1 because Unicode classifies it as "neutral".
// //
// // So we simply decide the width ourselves
// if (wc == 0x1F6E1) return 2;
//
// Well terminals do show it as width 1 after all
int width = widechar_wcwidth(wc);
switch (width) {
case widechar_ambiguous:
case widechar_private_use:
return 1;
case widechar_widened_in_9:
// Our renderer supports Unicode 9
return 2;
// case widechar_nonprint:
// case widechar_combining:
// case widechar_unassigned:
// case widechar_non_character:
// return -1;
default:
// Use the width widechar_width gave us.
return width;
}
}
+9 -9
View File
@@ -1,16 +1,16 @@
#pragma once
#include <wchar.h>
#include <stdint.h>
#ifdef FF_HAVE_WCWIDTH
static inline int mk_wcwidth(wchar_t ucs) {
return wcwidth(ucs);
}
static inline int mk_wcswidth(const wchar_t *pwcs, size_t n) {
return wcswidth(pwcs, n);
#include <wchar.h>
// Should be char32_t but it's not defined on macOS
static_assert(sizeof(wchar_t) == sizeof(uint32_t), "wcwidth implementation requires wchar_t to be 32 bits");
static inline int mk_wcwidth(uint32_t ucs) {
return wcwidth((wchar_t) ucs);
}
#else
// https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
int mk_wcwidth(wchar_t ucs);
int mk_wcswidth(const wchar_t *pwcs, size_t n);
int mk_wcwidth(uint32_t wc);
#endif
+42
View File
@@ -663,6 +663,48 @@ int main(void)
VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abc:", ':') == true);
VERIFY(ffStrbufMatchSeparatedS(&strbuf, "abc:", ':') == true);
VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abc", ':') == true);
VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":ABC", ':') == false);
VERIFY(ffStrbufMatchSeparatedS(&strbuf, ":abcdef", ':') == false);
}
{
ffStrbufSetStatic(&strbuf, "ABC");
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:def:ghi", ' ') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:def:ghi", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def:ghi", ' ') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def:ghi", ':') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "def", ':') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "", ' ') == false);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abc:", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, "abc:", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abc", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":ABC", ':') == true);
VERIFY(ffStrbufMatchSeparatedIgnCaseS(&strbuf, ":abcdef", ':') == false);
}
{
ffStrbufSetStatic(&strbuf, "abc:def:ghi");
VERIFY(ffStrbufSeparatedContainS(&strbuf, "abc", ' ') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "abc", ':') == true);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "def", ' ') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "def", ':') == true);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "DEF", ':') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "a", ':') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "e", ':') == false);
VERIFY(ffStrbufSeparatedContainS(&strbuf, "i", ':') == false);
}
{
ffStrbufSetStatic(&strbuf, "ABC:DEF:GHI");
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "abc", ' ') == false);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "abc", ':') == true);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "def", ' ') == false);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "def", ':') == true);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "DEF", ':') == true);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "a", ':') == false);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "e", ':') == false);
VERIFY(ffStrbufSeparatedContainIgnCaseS(&strbuf, "i", ':') == false);
}
{