diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c9ea24921..f0fd4973de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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,82 +225,18 @@ jobs: name: fastfetch-linux-armv6l path: ./fastfetch-*.* - linux-riscv64: - name: Linux-riscv64 - 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: 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 - 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-ppc64le - path: ./fastfetch-*.* - - linux-s390x: - name: Linux-s390x - 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 @@ -352,12 +245,12 @@ jobs: uses: uraimo/run-on-arch-action@v3 id: runcmd with: - arch: s390x + 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 @@ -370,7 +263,7 @@ jobs: - name: upload artifacts uses: actions/upload-artifact@v4 with: - name: fastfetch-linux-s390x + name: fastfetch-linux-${{ matrix.arch }} path: ./fastfetch-*.* musl-amd64: @@ -411,59 +304,19 @@ jobs: name: fastfetch-musl-amd64 path: ./fastfetch-*.* - macos-amd64: - name: macOS-amd64 - runs-on: macos-13 - 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-amd64 - path: ./fastfetch-*.* - - macos-aarch64: - name: macOS-aarch64 - runs-on: macos-latest + 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 @@ -502,7 +355,7 @@ jobs: - name: upload artifacts uses: actions/upload-artifact@v4 with: - name: fastfetch-macos-aarch64 + name: fastfetch-macos-${{ matrix.arch }} path: ./fastfetch-*.* sunos-amd64: @@ -718,74 +571,25 @@ jobs: name: fastfetch-haiku-amd64 path: ./fastfetch-*.* - windows-amd64: - name: Windows-amd64 - runs-on: windows-latest - 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: CLANG64 - 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 - - - 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 . - - - name: build project - run: cmake --build . --verbose -j4 - - - name: copy necessary dlls - run: cp /clang64/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-amd64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets - - - name: create 7z archive - run: 7z a -t7z -mx9 -bd -y fastfetch-windows-amd64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets - - - name: upload artifacts - uses: actions/upload-artifact@v4 - with: - name: fastfetch-windows-amd64 - path: ./fastfetch-windows-amd64.* - - windows-aarch64: - name: Windows-aarch64 - runs-on: windows-11-arm + 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} @@ -796,21 +600,21 @@ jobs: - name: setup-msys2 uses: msys2/setup-msys2@v2 with: - msystem: CLANGARM64 + msystem: ${{ matrix.msystem }} 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 + 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=/clangarm64/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 /clangarm64/bin/{OpenCL,vulkan-1}.dll . + run: cp /${{ matrix.msystem-lower }}/bin/{OpenCL,vulkan-1}.dll . - name: list features run: ./fastfetch --list-features @@ -831,39 +635,35 @@ jobs: 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 + run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets - name: create 7z archive - run: 7z a -t7z -mx9 -bd -y fastfetch-windows-aarch64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets + run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets - name: upload artifacts 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: diff --git a/CHANGELOG.md b/CHANGELOG.md index d74114c485..a07852c8f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: diff --git a/CMakeLists.txt b/CMakeLists.txt index f3b27dd425..be123fd7ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/debian/changelog b/debian/changelog index 1c96fee204..af24ca6109 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +fastfetch (2.52.0) jammy; urgency=medium + + * Update to 2.52.0 + + -- Carter Li Fri, 05 Sep 2025 14:59:44 +0800 + fastfetch (2.51.0) jammy; urgency=medium * Update to 2.51.0 diff --git a/debian/control b/debian/control index e161d94dc1..652c2336d8 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: fastfetch Section: universe/utils Priority: optional Maintainer: Carter Li -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 diff --git a/debian/files b/debian/files index e2ec8fa4cc..c5f654aa63 100644 --- a/debian/files +++ b/debian/files @@ -1 +1 @@ -fastfetch_2.51.0_source.buildinfo universe/utils optional +fastfetch_2.52.0_source.buildinfo universe/utils optional diff --git a/doc/json_schema.json b/doc/json_schema.json index 6152dd60df..d32269bd25 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -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 diff --git a/presets/examples/29.jsonc b/presets/examples/29.jsonc index 25b25a4c26..2dcd1c9b90 100644 --- a/presets/examples/29.jsonc +++ b/presets/examples/29.jsonc @@ -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": [ diff --git a/presets/examples/30.jsonc b/presets/examples/30.jsonc new file mode 100644 index 0000000000..5914c7d40c --- /dev/null +++ b/presets/examples/30.jsonc @@ -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 + } + ] +} diff --git a/src/3rdparty/mk_wcwidch/repo.json b/src/3rdparty/mk_wcwidch/repo.json deleted file mode 100644 index e44b953ba6..0000000000 --- a/src/3rdparty/mk_wcwidch/repo.json +++ /dev/null @@ -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" -} diff --git a/src/3rdparty/mk_wcwidch/wcwidth.c b/src/3rdparty/mk_wcwidch/wcwidth.c deleted file mode 100644 index 7abd26f98a..0000000000 --- a/src/3rdparty/mk_wcwidch/wcwidth.c +++ /dev/null @@ -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 - -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; -} diff --git a/src/3rdparty/widecharwidth/repo.json b/src/3rdparty/widecharwidth/repo.json new file mode 100644 index 0000000000..d87eb5f517 --- /dev/null +++ b/src/3rdparty/widecharwidth/repo.json @@ -0,0 +1,6 @@ +{ + "home": "https://github.com/ridiculousfish/widecharwidth", + "license": "Public domain", + "version": "Unicode 17", + "author": "ridiculousfish" +} diff --git a/src/3rdparty/widecharwidth/widechar_width_c.h b/src/3rdparty/widecharwidth/widechar_width_c.h new file mode 100644 index 0000000000..f13e8973ab --- /dev/null +++ b/src/3rdparty/widecharwidth/widechar_width_c.h @@ -0,0 +1,1590 @@ +/** + * widechar_width_c.h for Unicode 17.0.0 + * See https://github.com/ridiculousfish/widecharwidth/ + * + * SHA1 file hashes: + * ( + * the hashes for generate.py and the template are git object hashes, + * use `git log --all --find-object=` in the widecharwidth repository + * to see which commit they correspond to, + * or run `git hash-object` on the file to compare. + * The other hashes are simple `sha1sum` style hashes. + * ) + * + * generate.py: b35da43f176cc0d5880c67356ebb064048c5bac4 + * template.js: 1985fb56796d6d9627f9c5290d5dee9f9364bcf4 + * UnicodeData.txt: 50dffef1b7d1f97b72e4c2adceb9b2245f0f34ba + * EastAsianWidth.txt: 2cadc5034b6206ad84b75898a1d4186bb38fc12b + * emoji-data.txt: 3d123e12f70f63e609c4281ce83dfdd9ac7443d2 + */ + +#ifndef WIDECHAR_WIDTH_H +#define WIDECHAR_WIDTH_H + +#include +#include +#include + +#ifndef widechar_ARRAY_SIZE +#define widechar_ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) +#endif + +/* Special width values */ +enum { + widechar_nonprint = -1, // The character is not printable. + widechar_combining = -2, // The character is a zero-width combiner. + widechar_ambiguous = -3, // The character is East-Asian ambiguous width. + widechar_private_use = -4, // The character is for private use. + widechar_unassigned = -5, // The character is unassigned. + widechar_widened_in_9 = -6, // Width is 1 in Unicode 8, 2 in Unicode 9+. + widechar_non_character = -7 // The character is a noncharacter. +}; + +/* An inclusive range of characters. */ +struct widechar_range { + uint32_t lo; + uint32_t hi; +}; + +/* Simple ASCII characters - used a lot, so we check them first. */ +static const struct widechar_range widechar_ascii_table[] = { + {0x00020, 0x0007E} +}; + +/* Private usage range. */ +static const struct widechar_range widechar_private_table[] = { + {0x0E000, 0x0F8FF}, + {0xF0000, 0xFFFFD}, + {0x100000, 0x10FFFD} +}; + +/* Nonprinting characters. */ +static const struct widechar_range widechar_nonprint_table[] = { + {0x00000, 0x0001F}, + {0x0007F, 0x0009F}, + {0x000AD, 0x000AD}, + {0x00600, 0x00605}, + {0x0061C, 0x0061C}, + {0x006DD, 0x006DD}, + {0x0070F, 0x0070F}, + {0x00890, 0x00891}, + {0x008E2, 0x008E2}, + {0x0180E, 0x0180E}, + {0x0200B, 0x0200F}, + {0x02028, 0x0202E}, + {0x02060, 0x02064}, + {0x02066, 0x0206F}, + {0x0D800, 0x0DFFF}, + {0x0FEFF, 0x0FEFF}, + {0x0FFF9, 0x0FFFB}, + {0x110BD, 0x110BD}, + {0x110CD, 0x110CD}, + {0x13430, 0x1343F}, + {0x1BCA0, 0x1BCA3}, + {0x1D173, 0x1D17A}, + {0xE0001, 0xE0001}, + {0xE0020, 0xE007F} +}; + +/* Width 0 combining marks. */ +static const struct widechar_range widechar_combining_table[] = { + {0x00300, 0x0036F}, + {0x00483, 0x00489}, + {0x00591, 0x005BD}, + {0x005BF, 0x005BF}, + {0x005C1, 0x005C2}, + {0x005C4, 0x005C5}, + {0x005C7, 0x005C7}, + {0x00610, 0x0061A}, + {0x0064B, 0x0065F}, + {0x00670, 0x00670}, + {0x006D6, 0x006DC}, + {0x006DF, 0x006E4}, + {0x006E7, 0x006E8}, + {0x006EA, 0x006ED}, + {0x00711, 0x00711}, + {0x00730, 0x0074A}, + {0x007A6, 0x007B0}, + {0x007EB, 0x007F3}, + {0x007FD, 0x007FD}, + {0x00816, 0x00819}, + {0x0081B, 0x00823}, + {0x00825, 0x00827}, + {0x00829, 0x0082D}, + {0x00859, 0x0085B}, + {0x00897, 0x0089F}, + {0x008CA, 0x008E1}, + {0x008E3, 0x00903}, + {0x0093A, 0x0093C}, + {0x0093E, 0x0094F}, + {0x00951, 0x00957}, + {0x00962, 0x00963}, + {0x00981, 0x00983}, + {0x009BC, 0x009BC}, + {0x009BE, 0x009C4}, + {0x009C7, 0x009C8}, + {0x009CB, 0x009CD}, + {0x009D7, 0x009D7}, + {0x009E2, 0x009E3}, + {0x009FE, 0x009FE}, + {0x00A01, 0x00A03}, + {0x00A3C, 0x00A3C}, + {0x00A3E, 0x00A42}, + {0x00A47, 0x00A48}, + {0x00A4B, 0x00A4D}, + {0x00A51, 0x00A51}, + {0x00A70, 0x00A71}, + {0x00A75, 0x00A75}, + {0x00A81, 0x00A83}, + {0x00ABC, 0x00ABC}, + {0x00ABE, 0x00AC5}, + {0x00AC7, 0x00AC9}, + {0x00ACB, 0x00ACD}, + {0x00AE2, 0x00AE3}, + {0x00AFA, 0x00AFF}, + {0x00B01, 0x00B03}, + {0x00B3C, 0x00B3C}, + {0x00B3E, 0x00B44}, + {0x00B47, 0x00B48}, + {0x00B4B, 0x00B4D}, + {0x00B55, 0x00B57}, + {0x00B62, 0x00B63}, + {0x00B82, 0x00B82}, + {0x00BBE, 0x00BC2}, + {0x00BC6, 0x00BC8}, + {0x00BCA, 0x00BCD}, + {0x00BD7, 0x00BD7}, + {0x00C00, 0x00C04}, + {0x00C3C, 0x00C3C}, + {0x00C3E, 0x00C44}, + {0x00C46, 0x00C48}, + {0x00C4A, 0x00C4D}, + {0x00C55, 0x00C56}, + {0x00C62, 0x00C63}, + {0x00C81, 0x00C83}, + {0x00CBC, 0x00CBC}, + {0x00CBE, 0x00CC4}, + {0x00CC6, 0x00CC8}, + {0x00CCA, 0x00CCD}, + {0x00CD5, 0x00CD6}, + {0x00CE2, 0x00CE3}, + {0x00CF3, 0x00CF3}, + {0x00D00, 0x00D03}, + {0x00D3B, 0x00D3C}, + {0x00D3E, 0x00D44}, + {0x00D46, 0x00D48}, + {0x00D4A, 0x00D4D}, + {0x00D57, 0x00D57}, + {0x00D62, 0x00D63}, + {0x00D81, 0x00D83}, + {0x00DCA, 0x00DCA}, + {0x00DCF, 0x00DD4}, + {0x00DD6, 0x00DD6}, + {0x00DD8, 0x00DDF}, + {0x00DF2, 0x00DF3}, + {0x00E31, 0x00E31}, + {0x00E34, 0x00E3A}, + {0x00E47, 0x00E4E}, + {0x00EB1, 0x00EB1}, + {0x00EB4, 0x00EBC}, + {0x00EC8, 0x00ECE}, + {0x00F18, 0x00F19}, + {0x00F35, 0x00F35}, + {0x00F37, 0x00F37}, + {0x00F39, 0x00F39}, + {0x00F3E, 0x00F3F}, + {0x00F71, 0x00F84}, + {0x00F86, 0x00F87}, + {0x00F8D, 0x00F97}, + {0x00F99, 0x00FBC}, + {0x00FC6, 0x00FC6}, + {0x0102B, 0x0103E}, + {0x01056, 0x01059}, + {0x0105E, 0x01060}, + {0x01062, 0x01064}, + {0x01067, 0x0106D}, + {0x01071, 0x01074}, + {0x01082, 0x0108D}, + {0x0108F, 0x0108F}, + {0x0109A, 0x0109D}, + {0x0135D, 0x0135F}, + {0x01712, 0x01715}, + {0x01732, 0x01734}, + {0x01752, 0x01753}, + {0x01772, 0x01773}, + {0x017B4, 0x017D3}, + {0x017DD, 0x017DD}, + {0x0180B, 0x0180D}, + {0x0180F, 0x0180F}, + {0x01885, 0x01886}, + {0x018A9, 0x018A9}, + {0x01920, 0x0192B}, + {0x01930, 0x0193B}, + {0x01A17, 0x01A1B}, + {0x01A55, 0x01A5E}, + {0x01A60, 0x01A7C}, + {0x01A7F, 0x01A7F}, + {0x01AB0, 0x01ADD}, + {0x01AE0, 0x01AEB}, + {0x01B00, 0x01B04}, + {0x01B34, 0x01B44}, + {0x01B6B, 0x01B73}, + {0x01B80, 0x01B82}, + {0x01BA1, 0x01BAD}, + {0x01BE6, 0x01BF3}, + {0x01C24, 0x01C37}, + {0x01CD0, 0x01CD2}, + {0x01CD4, 0x01CE8}, + {0x01CED, 0x01CED}, + {0x01CF4, 0x01CF4}, + {0x01CF7, 0x01CF9}, + {0x01DC0, 0x01DFF}, + {0x020D0, 0x020F0}, + {0x02CEF, 0x02CF1}, + {0x02D7F, 0x02D7F}, + {0x02DE0, 0x02DFF}, + {0x0302A, 0x0302F}, + {0x03099, 0x0309A}, + {0x0A66F, 0x0A672}, + {0x0A674, 0x0A67D}, + {0x0A69E, 0x0A69F}, + {0x0A6F0, 0x0A6F1}, + {0x0A802, 0x0A802}, + {0x0A806, 0x0A806}, + {0x0A80B, 0x0A80B}, + {0x0A823, 0x0A827}, + {0x0A82C, 0x0A82C}, + {0x0A880, 0x0A881}, + {0x0A8B4, 0x0A8C5}, + {0x0A8E0, 0x0A8F1}, + {0x0A8FF, 0x0A8FF}, + {0x0A926, 0x0A92D}, + {0x0A947, 0x0A953}, + {0x0A980, 0x0A983}, + {0x0A9B3, 0x0A9C0}, + {0x0A9E5, 0x0A9E5}, + {0x0AA29, 0x0AA36}, + {0x0AA43, 0x0AA43}, + {0x0AA4C, 0x0AA4D}, + {0x0AA7B, 0x0AA7D}, + {0x0AAB0, 0x0AAB0}, + {0x0AAB2, 0x0AAB4}, + {0x0AAB7, 0x0AAB8}, + {0x0AABE, 0x0AABF}, + {0x0AAC1, 0x0AAC1}, + {0x0AAEB, 0x0AAEF}, + {0x0AAF5, 0x0AAF6}, + {0x0ABE3, 0x0ABEA}, + {0x0ABEC, 0x0ABED}, + {0x0FB1E, 0x0FB1E}, + {0x0FE00, 0x0FE0F}, + {0x0FE20, 0x0FE2F}, + {0x101FD, 0x101FD}, + {0x102E0, 0x102E0}, + {0x10376, 0x1037A}, + {0x10A01, 0x10A03}, + {0x10A05, 0x10A06}, + {0x10A0C, 0x10A0F}, + {0x10A38, 0x10A3A}, + {0x10A3F, 0x10A3F}, + {0x10AE5, 0x10AE6}, + {0x10D24, 0x10D27}, + {0x10D69, 0x10D6D}, + {0x10EAB, 0x10EAC}, + {0x10EFA, 0x10EFF}, + {0x10F46, 0x10F50}, + {0x10F82, 0x10F85}, + {0x11000, 0x11002}, + {0x11038, 0x11046}, + {0x11070, 0x11070}, + {0x11073, 0x11074}, + {0x1107F, 0x11082}, + {0x110B0, 0x110BA}, + {0x110C2, 0x110C2}, + {0x11100, 0x11102}, + {0x11127, 0x11134}, + {0x11145, 0x11146}, + {0x11173, 0x11173}, + {0x11180, 0x11182}, + {0x111B3, 0x111C0}, + {0x111C9, 0x111CC}, + {0x111CE, 0x111CF}, + {0x1122C, 0x11237}, + {0x1123E, 0x1123E}, + {0x11241, 0x11241}, + {0x112DF, 0x112EA}, + {0x11300, 0x11303}, + {0x1133B, 0x1133C}, + {0x1133E, 0x11344}, + {0x11347, 0x11348}, + {0x1134B, 0x1134D}, + {0x11357, 0x11357}, + {0x11362, 0x11363}, + {0x11366, 0x1136C}, + {0x11370, 0x11374}, + {0x113B8, 0x113C0}, + {0x113C2, 0x113C2}, + {0x113C5, 0x113C5}, + {0x113C7, 0x113CA}, + {0x113CC, 0x113D0}, + {0x113D2, 0x113D2}, + {0x113E1, 0x113E2}, + {0x11435, 0x11446}, + {0x1145E, 0x1145E}, + {0x114B0, 0x114C3}, + {0x115AF, 0x115B5}, + {0x115B8, 0x115C0}, + {0x115DC, 0x115DD}, + {0x11630, 0x11640}, + {0x116AB, 0x116B7}, + {0x1171D, 0x1172B}, + {0x1182C, 0x1183A}, + {0x11930, 0x11935}, + {0x11937, 0x11938}, + {0x1193B, 0x1193E}, + {0x11940, 0x11940}, + {0x11942, 0x11943}, + {0x119D1, 0x119D7}, + {0x119DA, 0x119E0}, + {0x119E4, 0x119E4}, + {0x11A01, 0x11A0A}, + {0x11A33, 0x11A39}, + {0x11A3B, 0x11A3E}, + {0x11A47, 0x11A47}, + {0x11A51, 0x11A5B}, + {0x11A8A, 0x11A99}, + {0x11B60, 0x11B67}, + {0x11C2F, 0x11C36}, + {0x11C38, 0x11C3F}, + {0x11C92, 0x11CA7}, + {0x11CA9, 0x11CB6}, + {0x11D31, 0x11D36}, + {0x11D3A, 0x11D3A}, + {0x11D3C, 0x11D3D}, + {0x11D3F, 0x11D45}, + {0x11D47, 0x11D47}, + {0x11D8A, 0x11D8E}, + {0x11D90, 0x11D91}, + {0x11D93, 0x11D97}, + {0x11EF3, 0x11EF6}, + {0x11F00, 0x11F01}, + {0x11F03, 0x11F03}, + {0x11F34, 0x11F3A}, + {0x11F3E, 0x11F42}, + {0x11F5A, 0x11F5A}, + {0x13440, 0x13440}, + {0x13447, 0x13455}, + {0x1611E, 0x1612F}, + {0x16AF0, 0x16AF4}, + {0x16B30, 0x16B36}, + {0x16F4F, 0x16F4F}, + {0x16F51, 0x16F87}, + {0x16F8F, 0x16F92}, + {0x16FE4, 0x16FE4}, + {0x16FF0, 0x16FF1}, + {0x1BC9D, 0x1BC9E}, + {0x1CF00, 0x1CF2D}, + {0x1CF30, 0x1CF46}, + {0x1D165, 0x1D169}, + {0x1D16D, 0x1D172}, + {0x1D17B, 0x1D182}, + {0x1D185, 0x1D18B}, + {0x1D1AA, 0x1D1AD}, + {0x1D242, 0x1D244}, + {0x1DA00, 0x1DA36}, + {0x1DA3B, 0x1DA6C}, + {0x1DA75, 0x1DA75}, + {0x1DA84, 0x1DA84}, + {0x1DA9B, 0x1DA9F}, + {0x1DAA1, 0x1DAAF}, + {0x1E000, 0x1E006}, + {0x1E008, 0x1E018}, + {0x1E01B, 0x1E021}, + {0x1E023, 0x1E024}, + {0x1E026, 0x1E02A}, + {0x1E08F, 0x1E08F}, + {0x1E130, 0x1E136}, + {0x1E2AE, 0x1E2AE}, + {0x1E2EC, 0x1E2EF}, + {0x1E4EC, 0x1E4EF}, + {0x1E5EE, 0x1E5EF}, + {0x1E6E3, 0x1E6E3}, + {0x1E6E6, 0x1E6E6}, + {0x1E6EE, 0x1E6EF}, + {0x1E6F5, 0x1E6F5}, + {0x1E8D0, 0x1E8D6}, + {0x1E944, 0x1E94A}, + {0xE0100, 0xE01EF} +}; + +/* Width 0 combining letters. */ +static const struct widechar_range widechar_combiningletters_table[] = { + {0x01160, 0x011FF}, + {0x0D7B0, 0x0D7FF} +}; + +/* Width 2 characters. */ +static const struct widechar_range widechar_doublewide_table[] = { + {0x01100, 0x0115F}, + {0x02329, 0x0232A}, + {0x02630, 0x02637}, + {0x0268A, 0x0268F}, + {0x02E80, 0x02E99}, + {0x02E9B, 0x02EF3}, + {0x02F00, 0x02FD5}, + {0x02FF0, 0x0303E}, + {0x03041, 0x03096}, + {0x03099, 0x030FF}, + {0x03105, 0x0312F}, + {0x03131, 0x0318E}, + {0x03190, 0x031E5}, + {0x031EF, 0x0321E}, + {0x03220, 0x03247}, + {0x03250, 0x0A48C}, + {0x0A490, 0x0A4C6}, + {0x0A960, 0x0A97C}, + {0x0AC00, 0x0D7A3}, + {0x0F900, 0x0FAFF}, + {0x0FE10, 0x0FE19}, + {0x0FE30, 0x0FE52}, + {0x0FE54, 0x0FE66}, + {0x0FE68, 0x0FE6B}, + {0x0FF01, 0x0FF60}, + {0x0FFE0, 0x0FFE6}, + {0x16FE0, 0x16FE4}, + {0x16FF0, 0x16FF6}, + {0x17000, 0x18CD5}, + {0x18CFF, 0x18D1E}, + {0x18D80, 0x18DF2}, + {0x1AFF0, 0x1AFF3}, + {0x1AFF5, 0x1AFFB}, + {0x1AFFD, 0x1AFFE}, + {0x1B000, 0x1B122}, + {0x1B132, 0x1B132}, + {0x1B150, 0x1B152}, + {0x1B155, 0x1B155}, + {0x1B164, 0x1B167}, + {0x1B170, 0x1B2FB}, + {0x1D300, 0x1D356}, + {0x1D360, 0x1D376}, + {0x1F200, 0x1F200}, + {0x1F202, 0x1F202}, + {0x1F210, 0x1F219}, + {0x1F21B, 0x1F22E}, + {0x1F230, 0x1F231}, + {0x1F237, 0x1F237}, + {0x1F23B, 0x1F23B}, + {0x1F240, 0x1F248}, + {0x1F260, 0x1F265}, + {0x1F57A, 0x1F57A}, + {0x1F5A4, 0x1F5A4}, + {0x1F6D1, 0x1F6D2}, + {0x1F6D5, 0x1F6D8}, + {0x1F6DC, 0x1F6DF}, + {0x1F6F4, 0x1F6FC}, + {0x1F7E0, 0x1F7EB}, + {0x1F7F0, 0x1F7F0}, + {0x1F90C, 0x1F90F}, + {0x1F919, 0x1F93A}, + {0x1F93C, 0x1F945}, + {0x1F947, 0x1F97F}, + {0x1F985, 0x1F9BF}, + {0x1F9C1, 0x1F9FF}, + {0x1FA70, 0x1FA7C}, + {0x1FA80, 0x1FA8A}, + {0x1FA8E, 0x1FAC6}, + {0x1FAC8, 0x1FAC8}, + {0x1FACD, 0x1FADC}, + {0x1FADF, 0x1FAEA}, + {0x1FAEF, 0x1FAF8}, + {0x20000, 0x2FFFD}, + {0x30000, 0x3FFFD} +}; + +/* Ambiguous-width characters. */ +static const struct widechar_range widechar_ambiguous_table[] = { + {0x000A1, 0x000A1}, + {0x000A4, 0x000A4}, + {0x000A7, 0x000A8}, + {0x000AA, 0x000AA}, + {0x000AD, 0x000AE}, + {0x000B0, 0x000B4}, + {0x000B6, 0x000BA}, + {0x000BC, 0x000BF}, + {0x000C6, 0x000C6}, + {0x000D0, 0x000D0}, + {0x000D7, 0x000D8}, + {0x000DE, 0x000E1}, + {0x000E6, 0x000E6}, + {0x000E8, 0x000EA}, + {0x000EC, 0x000ED}, + {0x000F0, 0x000F0}, + {0x000F2, 0x000F3}, + {0x000F7, 0x000FA}, + {0x000FC, 0x000FC}, + {0x000FE, 0x000FE}, + {0x00101, 0x00101}, + {0x00111, 0x00111}, + {0x00113, 0x00113}, + {0x0011B, 0x0011B}, + {0x00126, 0x00127}, + {0x0012B, 0x0012B}, + {0x00131, 0x00133}, + {0x00138, 0x00138}, + {0x0013F, 0x00142}, + {0x00144, 0x00144}, + {0x00148, 0x0014B}, + {0x0014D, 0x0014D}, + {0x00152, 0x00153}, + {0x00166, 0x00167}, + {0x0016B, 0x0016B}, + {0x001CE, 0x001CE}, + {0x001D0, 0x001D0}, + {0x001D2, 0x001D2}, + {0x001D4, 0x001D4}, + {0x001D6, 0x001D6}, + {0x001D8, 0x001D8}, + {0x001DA, 0x001DA}, + {0x001DC, 0x001DC}, + {0x00251, 0x00251}, + {0x00261, 0x00261}, + {0x002C4, 0x002C4}, + {0x002C7, 0x002C7}, + {0x002C9, 0x002CB}, + {0x002CD, 0x002CD}, + {0x002D0, 0x002D0}, + {0x002D8, 0x002DB}, + {0x002DD, 0x002DD}, + {0x002DF, 0x002DF}, + {0x00300, 0x0036F}, + {0x00391, 0x003A1}, + {0x003A3, 0x003A9}, + {0x003B1, 0x003C1}, + {0x003C3, 0x003C9}, + {0x00401, 0x00401}, + {0x00410, 0x0044F}, + {0x00451, 0x00451}, + {0x02010, 0x02010}, + {0x02013, 0x02016}, + {0x02018, 0x02019}, + {0x0201C, 0x0201D}, + {0x02020, 0x02022}, + {0x02024, 0x02027}, + {0x02030, 0x02030}, + {0x02032, 0x02033}, + {0x02035, 0x02035}, + {0x0203B, 0x0203B}, + {0x0203E, 0x0203E}, + {0x02074, 0x02074}, + {0x0207F, 0x0207F}, + {0x02081, 0x02084}, + {0x020AC, 0x020AC}, + {0x02103, 0x02103}, + {0x02105, 0x02105}, + {0x02109, 0x02109}, + {0x02113, 0x02113}, + {0x02116, 0x02116}, + {0x02121, 0x02122}, + {0x02126, 0x02126}, + {0x0212B, 0x0212B}, + {0x02153, 0x02154}, + {0x0215B, 0x0215E}, + {0x02160, 0x0216B}, + {0x02170, 0x02179}, + {0x02189, 0x02189}, + {0x02190, 0x02199}, + {0x021B8, 0x021B9}, + {0x021D2, 0x021D2}, + {0x021D4, 0x021D4}, + {0x021E7, 0x021E7}, + {0x02200, 0x02200}, + {0x02202, 0x02203}, + {0x02207, 0x02208}, + {0x0220B, 0x0220B}, + {0x0220F, 0x0220F}, + {0x02211, 0x02211}, + {0x02215, 0x02215}, + {0x0221A, 0x0221A}, + {0x0221D, 0x02220}, + {0x02223, 0x02223}, + {0x02225, 0x02225}, + {0x02227, 0x0222C}, + {0x0222E, 0x0222E}, + {0x02234, 0x02237}, + {0x0223C, 0x0223D}, + {0x02248, 0x02248}, + {0x0224C, 0x0224C}, + {0x02252, 0x02252}, + {0x02260, 0x02261}, + {0x02264, 0x02267}, + {0x0226A, 0x0226B}, + {0x0226E, 0x0226F}, + {0x02282, 0x02283}, + {0x02286, 0x02287}, + {0x02295, 0x02295}, + {0x02299, 0x02299}, + {0x022A5, 0x022A5}, + {0x022BF, 0x022BF}, + {0x02312, 0x02312}, + {0x02460, 0x024E9}, + {0x024EB, 0x0254B}, + {0x02550, 0x02573}, + {0x02580, 0x0258F}, + {0x02592, 0x02595}, + {0x025A0, 0x025A1}, + {0x025A3, 0x025A9}, + {0x025B2, 0x025B3}, + {0x025B6, 0x025B7}, + {0x025BC, 0x025BD}, + {0x025C0, 0x025C1}, + {0x025C6, 0x025C8}, + {0x025CB, 0x025CB}, + {0x025CE, 0x025D1}, + {0x025E2, 0x025E5}, + {0x025EF, 0x025EF}, + {0x02605, 0x02606}, + {0x02609, 0x02609}, + {0x0260E, 0x0260F}, + {0x0261C, 0x0261C}, + {0x0261E, 0x0261E}, + {0x02640, 0x02640}, + {0x02642, 0x02642}, + {0x02660, 0x02661}, + {0x02663, 0x02665}, + {0x02667, 0x0266A}, + {0x0266C, 0x0266D}, + {0x0266F, 0x0266F}, + {0x0269E, 0x0269F}, + {0x026BF, 0x026BF}, + {0x026C6, 0x026CD}, + {0x026CF, 0x026D3}, + {0x026D5, 0x026E1}, + {0x026E3, 0x026E3}, + {0x026E8, 0x026E9}, + {0x026EB, 0x026F1}, + {0x026F4, 0x026F4}, + {0x026F6, 0x026F9}, + {0x026FB, 0x026FC}, + {0x026FE, 0x026FF}, + {0x0273D, 0x0273D}, + {0x02776, 0x0277F}, + {0x02B56, 0x02B59}, + {0x03248, 0x0324F}, + {0x0E000, 0x0F8FF}, + {0x0FE00, 0x0FE0F}, + {0x0FFFD, 0x0FFFD}, + {0x1F100, 0x1F10A}, + {0x1F110, 0x1F12D}, + {0x1F130, 0x1F169}, + {0x1F170, 0x1F18D}, + {0x1F18F, 0x1F190}, + {0x1F19B, 0x1F1AC}, + {0xE0100, 0xE01EF}, + {0xF0000, 0xFFFFD}, + {0x100000, 0x10FFFD} +}; + +/* Unassigned characters. */ +static const struct widechar_range widechar_unassigned_table[] = { + {0x00378, 0x00379}, + {0x00380, 0x00383}, + {0x0038B, 0x0038B}, + {0x0038D, 0x0038D}, + {0x003A2, 0x003A2}, + {0x00530, 0x00530}, + {0x00557, 0x00558}, + {0x0058B, 0x0058C}, + {0x00590, 0x00590}, + {0x005C8, 0x005CF}, + {0x005EB, 0x005EE}, + {0x005F5, 0x005FF}, + {0x0070E, 0x0070E}, + {0x0074B, 0x0074C}, + {0x007B2, 0x007BF}, + {0x007FB, 0x007FC}, + {0x0082E, 0x0082F}, + {0x0083F, 0x0083F}, + {0x0085C, 0x0085D}, + {0x0085F, 0x0085F}, + {0x0086B, 0x0086F}, + {0x00892, 0x00896}, + {0x00984, 0x00984}, + {0x0098D, 0x0098E}, + {0x00991, 0x00992}, + {0x009A9, 0x009A9}, + {0x009B1, 0x009B1}, + {0x009B3, 0x009B5}, + {0x009BA, 0x009BB}, + {0x009C5, 0x009C6}, + {0x009C9, 0x009CA}, + {0x009CF, 0x009D6}, + {0x009D8, 0x009DB}, + {0x009DE, 0x009DE}, + {0x009E4, 0x009E5}, + {0x009FF, 0x00A00}, + {0x00A04, 0x00A04}, + {0x00A0B, 0x00A0E}, + {0x00A11, 0x00A12}, + {0x00A29, 0x00A29}, + {0x00A31, 0x00A31}, + {0x00A34, 0x00A34}, + {0x00A37, 0x00A37}, + {0x00A3A, 0x00A3B}, + {0x00A3D, 0x00A3D}, + {0x00A43, 0x00A46}, + {0x00A49, 0x00A4A}, + {0x00A4E, 0x00A50}, + {0x00A52, 0x00A58}, + {0x00A5D, 0x00A5D}, + {0x00A5F, 0x00A65}, + {0x00A77, 0x00A80}, + {0x00A84, 0x00A84}, + {0x00A8E, 0x00A8E}, + {0x00A92, 0x00A92}, + {0x00AA9, 0x00AA9}, + {0x00AB1, 0x00AB1}, + {0x00AB4, 0x00AB4}, + {0x00ABA, 0x00ABB}, + {0x00AC6, 0x00AC6}, + {0x00ACA, 0x00ACA}, + {0x00ACE, 0x00ACF}, + {0x00AD1, 0x00ADF}, + {0x00AE4, 0x00AE5}, + {0x00AF2, 0x00AF8}, + {0x00B00, 0x00B00}, + {0x00B04, 0x00B04}, + {0x00B0D, 0x00B0E}, + {0x00B11, 0x00B12}, + {0x00B29, 0x00B29}, + {0x00B31, 0x00B31}, + {0x00B34, 0x00B34}, + {0x00B3A, 0x00B3B}, + {0x00B45, 0x00B46}, + {0x00B49, 0x00B4A}, + {0x00B4E, 0x00B54}, + {0x00B58, 0x00B5B}, + {0x00B5E, 0x00B5E}, + {0x00B64, 0x00B65}, + {0x00B78, 0x00B81}, + {0x00B84, 0x00B84}, + {0x00B8B, 0x00B8D}, + {0x00B91, 0x00B91}, + {0x00B96, 0x00B98}, + {0x00B9B, 0x00B9B}, + {0x00B9D, 0x00B9D}, + {0x00BA0, 0x00BA2}, + {0x00BA5, 0x00BA7}, + {0x00BAB, 0x00BAD}, + {0x00BBA, 0x00BBD}, + {0x00BC3, 0x00BC5}, + {0x00BC9, 0x00BC9}, + {0x00BCE, 0x00BCF}, + {0x00BD1, 0x00BD6}, + {0x00BD8, 0x00BE5}, + {0x00BFB, 0x00BFF}, + {0x00C0D, 0x00C0D}, + {0x00C11, 0x00C11}, + {0x00C29, 0x00C29}, + {0x00C3A, 0x00C3B}, + {0x00C45, 0x00C45}, + {0x00C49, 0x00C49}, + {0x00C4E, 0x00C54}, + {0x00C57, 0x00C57}, + {0x00C5B, 0x00C5B}, + {0x00C5E, 0x00C5F}, + {0x00C64, 0x00C65}, + {0x00C70, 0x00C76}, + {0x00C8D, 0x00C8D}, + {0x00C91, 0x00C91}, + {0x00CA9, 0x00CA9}, + {0x00CB4, 0x00CB4}, + {0x00CBA, 0x00CBB}, + {0x00CC5, 0x00CC5}, + {0x00CC9, 0x00CC9}, + {0x00CCE, 0x00CD4}, + {0x00CD7, 0x00CDB}, + {0x00CDF, 0x00CDF}, + {0x00CE4, 0x00CE5}, + {0x00CF0, 0x00CF0}, + {0x00CF4, 0x00CFF}, + {0x00D0D, 0x00D0D}, + {0x00D11, 0x00D11}, + {0x00D45, 0x00D45}, + {0x00D49, 0x00D49}, + {0x00D50, 0x00D53}, + {0x00D64, 0x00D65}, + {0x00D80, 0x00D80}, + {0x00D84, 0x00D84}, + {0x00D97, 0x00D99}, + {0x00DB2, 0x00DB2}, + {0x00DBC, 0x00DBC}, + {0x00DBE, 0x00DBF}, + {0x00DC7, 0x00DC9}, + {0x00DCB, 0x00DCE}, + {0x00DD5, 0x00DD5}, + {0x00DD7, 0x00DD7}, + {0x00DE0, 0x00DE5}, + {0x00DF0, 0x00DF1}, + {0x00DF5, 0x00E00}, + {0x00E3B, 0x00E3E}, + {0x00E5C, 0x00E80}, + {0x00E83, 0x00E83}, + {0x00E85, 0x00E85}, + {0x00E8B, 0x00E8B}, + {0x00EA4, 0x00EA4}, + {0x00EA6, 0x00EA6}, + {0x00EBE, 0x00EBF}, + {0x00EC5, 0x00EC5}, + {0x00EC7, 0x00EC7}, + {0x00ECF, 0x00ECF}, + {0x00EDA, 0x00EDB}, + {0x00EE0, 0x00EFF}, + {0x00F48, 0x00F48}, + {0x00F6D, 0x00F70}, + {0x00F98, 0x00F98}, + {0x00FBD, 0x00FBD}, + {0x00FCD, 0x00FCD}, + {0x00FDB, 0x00FFF}, + {0x010C6, 0x010C6}, + {0x010C8, 0x010CC}, + {0x010CE, 0x010CF}, + {0x01249, 0x01249}, + {0x0124E, 0x0124F}, + {0x01257, 0x01257}, + {0x01259, 0x01259}, + {0x0125E, 0x0125F}, + {0x01289, 0x01289}, + {0x0128E, 0x0128F}, + {0x012B1, 0x012B1}, + {0x012B6, 0x012B7}, + {0x012BF, 0x012BF}, + {0x012C1, 0x012C1}, + {0x012C6, 0x012C7}, + {0x012D7, 0x012D7}, + {0x01311, 0x01311}, + {0x01316, 0x01317}, + {0x0135B, 0x0135C}, + {0x0137D, 0x0137F}, + {0x0139A, 0x0139F}, + {0x013F6, 0x013F7}, + {0x013FE, 0x013FF}, + {0x0169D, 0x0169F}, + {0x016F9, 0x016FF}, + {0x01716, 0x0171E}, + {0x01737, 0x0173F}, + {0x01754, 0x0175F}, + {0x0176D, 0x0176D}, + {0x01771, 0x01771}, + {0x01774, 0x0177F}, + {0x017DE, 0x017DF}, + {0x017EA, 0x017EF}, + {0x017FA, 0x017FF}, + {0x0181A, 0x0181F}, + {0x01879, 0x0187F}, + {0x018AB, 0x018AF}, + {0x018F6, 0x018FF}, + {0x0191F, 0x0191F}, + {0x0192C, 0x0192F}, + {0x0193C, 0x0193F}, + {0x01941, 0x01943}, + {0x0196E, 0x0196F}, + {0x01975, 0x0197F}, + {0x019AC, 0x019AF}, + {0x019CA, 0x019CF}, + {0x019DB, 0x019DD}, + {0x01A1C, 0x01A1D}, + {0x01A5F, 0x01A5F}, + {0x01A7D, 0x01A7E}, + {0x01A8A, 0x01A8F}, + {0x01A9A, 0x01A9F}, + {0x01AAE, 0x01AAF}, + {0x01ADE, 0x01ADF}, + {0x01AEC, 0x01AFF}, + {0x01B4D, 0x01B4D}, + {0x01BF4, 0x01BFB}, + {0x01C38, 0x01C3A}, + {0x01C4A, 0x01C4C}, + {0x01C8B, 0x01C8F}, + {0x01CBB, 0x01CBC}, + {0x01CC8, 0x01CCF}, + {0x01CFB, 0x01CFF}, + {0x01F16, 0x01F17}, + {0x01F1E, 0x01F1F}, + {0x01F46, 0x01F47}, + {0x01F4E, 0x01F4F}, + {0x01F58, 0x01F58}, + {0x01F5A, 0x01F5A}, + {0x01F5C, 0x01F5C}, + {0x01F5E, 0x01F5E}, + {0x01F7E, 0x01F7F}, + {0x01FB5, 0x01FB5}, + {0x01FC5, 0x01FC5}, + {0x01FD4, 0x01FD5}, + {0x01FDC, 0x01FDC}, + {0x01FF0, 0x01FF1}, + {0x01FF5, 0x01FF5}, + {0x01FFF, 0x01FFF}, + {0x02065, 0x02065}, + {0x02072, 0x02073}, + {0x0208F, 0x0208F}, + {0x0209D, 0x0209F}, + {0x020C2, 0x020CF}, + {0x020F1, 0x020FF}, + {0x0218C, 0x0218F}, + {0x0242A, 0x0243F}, + {0x0244B, 0x0245F}, + {0x02B74, 0x02B75}, + {0x02CF4, 0x02CF8}, + {0x02D26, 0x02D26}, + {0x02D28, 0x02D2C}, + {0x02D2E, 0x02D2F}, + {0x02D68, 0x02D6E}, + {0x02D71, 0x02D7E}, + {0x02D97, 0x02D9F}, + {0x02DA7, 0x02DA7}, + {0x02DAF, 0x02DAF}, + {0x02DB7, 0x02DB7}, + {0x02DBF, 0x02DBF}, + {0x02DC7, 0x02DC7}, + {0x02DCF, 0x02DCF}, + {0x02DD7, 0x02DD7}, + {0x02DDF, 0x02DDF}, + {0x02E5E, 0x02E7F}, + {0x02E9A, 0x02E9A}, + {0x02EF4, 0x02EFF}, + {0x02FD6, 0x02FEF}, + {0x03040, 0x03040}, + {0x03097, 0x03098}, + {0x03100, 0x03104}, + {0x03130, 0x03130}, + {0x0318F, 0x0318F}, + {0x031E6, 0x031EE}, + {0x0321F, 0x0321F}, + {0x03401, 0x04DBE}, + {0x04E01, 0x09FFE}, + {0x0A48D, 0x0A48F}, + {0x0A4C7, 0x0A4CF}, + {0x0A62C, 0x0A63F}, + {0x0A6F8, 0x0A6FF}, + {0x0A7DD, 0x0A7F0}, + {0x0A82D, 0x0A82F}, + {0x0A83A, 0x0A83F}, + {0x0A878, 0x0A87F}, + {0x0A8C6, 0x0A8CD}, + {0x0A8DA, 0x0A8DF}, + {0x0A954, 0x0A95E}, + {0x0A97D, 0x0A97F}, + {0x0A9CE, 0x0A9CE}, + {0x0A9DA, 0x0A9DD}, + {0x0A9FF, 0x0A9FF}, + {0x0AA37, 0x0AA3F}, + {0x0AA4E, 0x0AA4F}, + {0x0AA5A, 0x0AA5B}, + {0x0AAC3, 0x0AADA}, + {0x0AAF7, 0x0AB00}, + {0x0AB07, 0x0AB08}, + {0x0AB0F, 0x0AB10}, + {0x0AB17, 0x0AB1F}, + {0x0AB27, 0x0AB27}, + {0x0AB2F, 0x0AB2F}, + {0x0AB6C, 0x0AB6F}, + {0x0ABEE, 0x0ABEF}, + {0x0ABFA, 0x0ABFF}, + {0x0AC01, 0x0D7A2}, + {0x0D7A4, 0x0D7AF}, + {0x0D7C7, 0x0D7CA}, + {0x0D7FC, 0x0D7FF}, + {0x0FA6E, 0x0FA6F}, + {0x0FADA, 0x0FAFF}, + {0x0FB07, 0x0FB12}, + {0x0FB18, 0x0FB1C}, + {0x0FB37, 0x0FB37}, + {0x0FB3D, 0x0FB3D}, + {0x0FB3F, 0x0FB3F}, + {0x0FB42, 0x0FB42}, + {0x0FB45, 0x0FB45}, + {0x0FE1A, 0x0FE1F}, + {0x0FE53, 0x0FE53}, + {0x0FE67, 0x0FE67}, + {0x0FE6C, 0x0FE6F}, + {0x0FE75, 0x0FE75}, + {0x0FEFD, 0x0FEFE}, + {0x0FF00, 0x0FF00}, + {0x0FFBF, 0x0FFC1}, + {0x0FFC8, 0x0FFC9}, + {0x0FFD0, 0x0FFD1}, + {0x0FFD8, 0x0FFD9}, + {0x0FFDD, 0x0FFDF}, + {0x0FFE7, 0x0FFE7}, + {0x0FFEF, 0x0FFF8}, + {0x1000C, 0x1000C}, + {0x10027, 0x10027}, + {0x1003B, 0x1003B}, + {0x1003E, 0x1003E}, + {0x1004E, 0x1004F}, + {0x1005E, 0x1007F}, + {0x100FB, 0x100FF}, + {0x10103, 0x10106}, + {0x10134, 0x10136}, + {0x1018F, 0x1018F}, + {0x1019D, 0x1019F}, + {0x101A1, 0x101CF}, + {0x101FE, 0x1027F}, + {0x1029D, 0x1029F}, + {0x102D1, 0x102DF}, + {0x102FC, 0x102FF}, + {0x10324, 0x1032C}, + {0x1034B, 0x1034F}, + {0x1037B, 0x1037F}, + {0x1039E, 0x1039E}, + {0x103C4, 0x103C7}, + {0x103D6, 0x103FF}, + {0x1049E, 0x1049F}, + {0x104AA, 0x104AF}, + {0x104D4, 0x104D7}, + {0x104FC, 0x104FF}, + {0x10528, 0x1052F}, + {0x10564, 0x1056E}, + {0x1057B, 0x1057B}, + {0x1058B, 0x1058B}, + {0x10593, 0x10593}, + {0x10596, 0x10596}, + {0x105A2, 0x105A2}, + {0x105B2, 0x105B2}, + {0x105BA, 0x105BA}, + {0x105BD, 0x105BF}, + {0x105F4, 0x105FF}, + {0x10737, 0x1073F}, + {0x10756, 0x1075F}, + {0x10768, 0x1077F}, + {0x10786, 0x10786}, + {0x107B1, 0x107B1}, + {0x107BB, 0x107FF}, + {0x10806, 0x10807}, + {0x10809, 0x10809}, + {0x10836, 0x10836}, + {0x10839, 0x1083B}, + {0x1083D, 0x1083E}, + {0x10856, 0x10856}, + {0x1089F, 0x108A6}, + {0x108B0, 0x108DF}, + {0x108F3, 0x108F3}, + {0x108F6, 0x108FA}, + {0x1091C, 0x1091E}, + {0x1093A, 0x1093E}, + {0x1095A, 0x1097F}, + {0x109B8, 0x109BB}, + {0x109D0, 0x109D1}, + {0x10A04, 0x10A04}, + {0x10A07, 0x10A0B}, + {0x10A14, 0x10A14}, + {0x10A18, 0x10A18}, + {0x10A36, 0x10A37}, + {0x10A3B, 0x10A3E}, + {0x10A49, 0x10A4F}, + {0x10A59, 0x10A5F}, + {0x10AA0, 0x10ABF}, + {0x10AE7, 0x10AEA}, + {0x10AF7, 0x10AFF}, + {0x10B36, 0x10B38}, + {0x10B56, 0x10B57}, + {0x10B73, 0x10B77}, + {0x10B92, 0x10B98}, + {0x10B9D, 0x10BA8}, + {0x10BB0, 0x10BFF}, + {0x10C49, 0x10C7F}, + {0x10CB3, 0x10CBF}, + {0x10CF3, 0x10CF9}, + {0x10D28, 0x10D2F}, + {0x10D3A, 0x10D3F}, + {0x10D66, 0x10D68}, + {0x10D86, 0x10D8D}, + {0x10D90, 0x10E5F}, + {0x10E7F, 0x10E7F}, + {0x10EAA, 0x10EAA}, + {0x10EAE, 0x10EAF}, + {0x10EB2, 0x10EC1}, + {0x10EC8, 0x10ECF}, + {0x10ED9, 0x10EF9}, + {0x10F28, 0x10F2F}, + {0x10F5A, 0x10F6F}, + {0x10F8A, 0x10FAF}, + {0x10FCC, 0x10FDF}, + {0x10FF7, 0x10FFF}, + {0x1104E, 0x11051}, + {0x11076, 0x1107E}, + {0x110C3, 0x110CC}, + {0x110CE, 0x110CF}, + {0x110E9, 0x110EF}, + {0x110FA, 0x110FF}, + {0x11135, 0x11135}, + {0x11148, 0x1114F}, + {0x11177, 0x1117F}, + {0x111E0, 0x111E0}, + {0x111F5, 0x111FF}, + {0x11212, 0x11212}, + {0x11242, 0x1127F}, + {0x11287, 0x11287}, + {0x11289, 0x11289}, + {0x1128E, 0x1128E}, + {0x1129E, 0x1129E}, + {0x112AA, 0x112AF}, + {0x112EB, 0x112EF}, + {0x112FA, 0x112FF}, + {0x11304, 0x11304}, + {0x1130D, 0x1130E}, + {0x11311, 0x11312}, + {0x11329, 0x11329}, + {0x11331, 0x11331}, + {0x11334, 0x11334}, + {0x1133A, 0x1133A}, + {0x11345, 0x11346}, + {0x11349, 0x1134A}, + {0x1134E, 0x1134F}, + {0x11351, 0x11356}, + {0x11358, 0x1135C}, + {0x11364, 0x11365}, + {0x1136D, 0x1136F}, + {0x11375, 0x1137F}, + {0x1138A, 0x1138A}, + {0x1138C, 0x1138D}, + {0x1138F, 0x1138F}, + {0x113B6, 0x113B6}, + {0x113C1, 0x113C1}, + {0x113C3, 0x113C4}, + {0x113C6, 0x113C6}, + {0x113CB, 0x113CB}, + {0x113D6, 0x113D6}, + {0x113D9, 0x113E0}, + {0x113E3, 0x113FF}, + {0x1145C, 0x1145C}, + {0x11462, 0x1147F}, + {0x114C8, 0x114CF}, + {0x114DA, 0x1157F}, + {0x115B6, 0x115B7}, + {0x115DE, 0x115FF}, + {0x11645, 0x1164F}, + {0x1165A, 0x1165F}, + {0x1166D, 0x1167F}, + {0x116BA, 0x116BF}, + {0x116CA, 0x116CF}, + {0x116E4, 0x116FF}, + {0x1171B, 0x1171C}, + {0x1172C, 0x1172F}, + {0x11747, 0x117FF}, + {0x1183C, 0x1189F}, + {0x118F3, 0x118FE}, + {0x11907, 0x11908}, + {0x1190A, 0x1190B}, + {0x11914, 0x11914}, + {0x11917, 0x11917}, + {0x11936, 0x11936}, + {0x11939, 0x1193A}, + {0x11947, 0x1194F}, + {0x1195A, 0x1199F}, + {0x119A8, 0x119A9}, + {0x119D8, 0x119D9}, + {0x119E5, 0x119FF}, + {0x11A48, 0x11A4F}, + {0x11AA3, 0x11AAF}, + {0x11AF9, 0x11AFF}, + {0x11B0A, 0x11B5F}, + {0x11B68, 0x11BBF}, + {0x11BE2, 0x11BEF}, + {0x11BFA, 0x11BFF}, + {0x11C09, 0x11C09}, + {0x11C37, 0x11C37}, + {0x11C46, 0x11C4F}, + {0x11C6D, 0x11C6F}, + {0x11C90, 0x11C91}, + {0x11CA8, 0x11CA8}, + {0x11CB7, 0x11CFF}, + {0x11D07, 0x11D07}, + {0x11D0A, 0x11D0A}, + {0x11D37, 0x11D39}, + {0x11D3B, 0x11D3B}, + {0x11D3E, 0x11D3E}, + {0x11D48, 0x11D4F}, + {0x11D5A, 0x11D5F}, + {0x11D66, 0x11D66}, + {0x11D69, 0x11D69}, + {0x11D8F, 0x11D8F}, + {0x11D92, 0x11D92}, + {0x11D99, 0x11D9F}, + {0x11DAA, 0x11DAF}, + {0x11DDC, 0x11DDF}, + {0x11DEA, 0x11EDF}, + {0x11EF9, 0x11EFF}, + {0x11F11, 0x11F11}, + {0x11F3B, 0x11F3D}, + {0x11F5B, 0x11FAF}, + {0x11FB1, 0x11FBF}, + {0x11FF2, 0x11FFE}, + {0x1239A, 0x123FF}, + {0x1246F, 0x1246F}, + {0x12475, 0x1247F}, + {0x12544, 0x12F8F}, + {0x12FF3, 0x12FFF}, + {0x13456, 0x1345F}, + {0x143FB, 0x143FF}, + {0x14647, 0x160FF}, + {0x1613A, 0x167FF}, + {0x16A39, 0x16A3F}, + {0x16A5F, 0x16A5F}, + {0x16A6A, 0x16A6D}, + {0x16ABF, 0x16ABF}, + {0x16ACA, 0x16ACF}, + {0x16AEE, 0x16AEF}, + {0x16AF6, 0x16AFF}, + {0x16B46, 0x16B4F}, + {0x16B5A, 0x16B5A}, + {0x16B62, 0x16B62}, + {0x16B78, 0x16B7C}, + {0x16B90, 0x16D3F}, + {0x16D7A, 0x16E3F}, + {0x16E9B, 0x16E9F}, + {0x16EB9, 0x16EBA}, + {0x16ED4, 0x16EFF}, + {0x16F4B, 0x16F4E}, + {0x16F88, 0x16F8E}, + {0x16FA0, 0x16FDF}, + {0x16FE5, 0x16FEF}, + {0x16FF7, 0x16FFF}, + {0x17001, 0x187FE}, + {0x18CD6, 0x18CFE}, + {0x18D01, 0x18D1D}, + {0x18D1F, 0x18D7F}, + {0x18DF3, 0x1AFEF}, + {0x1AFF4, 0x1AFF4}, + {0x1AFFC, 0x1AFFC}, + {0x1AFFF, 0x1AFFF}, + {0x1B123, 0x1B131}, + {0x1B133, 0x1B14F}, + {0x1B153, 0x1B154}, + {0x1B156, 0x1B163}, + {0x1B168, 0x1B16F}, + {0x1B2FC, 0x1BBFF}, + {0x1BC6B, 0x1BC6F}, + {0x1BC7D, 0x1BC7F}, + {0x1BC89, 0x1BC8F}, + {0x1BC9A, 0x1BC9B}, + {0x1BCA4, 0x1CBFF}, + {0x1CCFD, 0x1CCFF}, + {0x1CEB4, 0x1CEB9}, + {0x1CED1, 0x1CEDF}, + {0x1CEF1, 0x1CEFF}, + {0x1CF2E, 0x1CF2F}, + {0x1CF47, 0x1CF4F}, + {0x1CFC4, 0x1CFFF}, + {0x1D0F6, 0x1D0FF}, + {0x1D127, 0x1D128}, + {0x1D1EB, 0x1D1FF}, + {0x1D246, 0x1D2BF}, + {0x1D2D4, 0x1D2DF}, + {0x1D2F4, 0x1D2FF}, + {0x1D357, 0x1D35F}, + {0x1D379, 0x1D3FF}, + {0x1D455, 0x1D455}, + {0x1D49D, 0x1D49D}, + {0x1D4A0, 0x1D4A1}, + {0x1D4A3, 0x1D4A4}, + {0x1D4A7, 0x1D4A8}, + {0x1D4AD, 0x1D4AD}, + {0x1D4BA, 0x1D4BA}, + {0x1D4BC, 0x1D4BC}, + {0x1D4C4, 0x1D4C4}, + {0x1D506, 0x1D506}, + {0x1D50B, 0x1D50C}, + {0x1D515, 0x1D515}, + {0x1D51D, 0x1D51D}, + {0x1D53A, 0x1D53A}, + {0x1D53F, 0x1D53F}, + {0x1D545, 0x1D545}, + {0x1D547, 0x1D549}, + {0x1D551, 0x1D551}, + {0x1D6A6, 0x1D6A7}, + {0x1D7CC, 0x1D7CD}, + {0x1DA8C, 0x1DA9A}, + {0x1DAA0, 0x1DAA0}, + {0x1DAB0, 0x1DEFF}, + {0x1DF1F, 0x1DF24}, + {0x1DF2B, 0x1DFFF}, + {0x1E007, 0x1E007}, + {0x1E019, 0x1E01A}, + {0x1E022, 0x1E022}, + {0x1E025, 0x1E025}, + {0x1E02B, 0x1E02F}, + {0x1E06E, 0x1E08E}, + {0x1E090, 0x1E0FF}, + {0x1E12D, 0x1E12F}, + {0x1E13E, 0x1E13F}, + {0x1E14A, 0x1E14D}, + {0x1E150, 0x1E28F}, + {0x1E2AF, 0x1E2BF}, + {0x1E2FA, 0x1E2FE}, + {0x1E300, 0x1E4CF}, + {0x1E4FA, 0x1E5CF}, + {0x1E5FB, 0x1E5FE}, + {0x1E600, 0x1E6BF}, + {0x1E6DF, 0x1E6DF}, + {0x1E6F6, 0x1E6FD}, + {0x1E700, 0x1E7DF}, + {0x1E7E7, 0x1E7E7}, + {0x1E7EC, 0x1E7EC}, + {0x1E7EF, 0x1E7EF}, + {0x1E7FF, 0x1E7FF}, + {0x1E8C5, 0x1E8C6}, + {0x1E8D7, 0x1E8FF}, + {0x1E94C, 0x1E94F}, + {0x1E95A, 0x1E95D}, + {0x1E960, 0x1EC70}, + {0x1ECB5, 0x1ED00}, + {0x1ED3E, 0x1EDFF}, + {0x1EE04, 0x1EE04}, + {0x1EE20, 0x1EE20}, + {0x1EE23, 0x1EE23}, + {0x1EE25, 0x1EE26}, + {0x1EE28, 0x1EE28}, + {0x1EE33, 0x1EE33}, + {0x1EE38, 0x1EE38}, + {0x1EE3A, 0x1EE3A}, + {0x1EE3C, 0x1EE41}, + {0x1EE43, 0x1EE46}, + {0x1EE48, 0x1EE48}, + {0x1EE4A, 0x1EE4A}, + {0x1EE4C, 0x1EE4C}, + {0x1EE50, 0x1EE50}, + {0x1EE53, 0x1EE53}, + {0x1EE55, 0x1EE56}, + {0x1EE58, 0x1EE58}, + {0x1EE5A, 0x1EE5A}, + {0x1EE5C, 0x1EE5C}, + {0x1EE5E, 0x1EE5E}, + {0x1EE60, 0x1EE60}, + {0x1EE63, 0x1EE63}, + {0x1EE65, 0x1EE66}, + {0x1EE6B, 0x1EE6B}, + {0x1EE73, 0x1EE73}, + {0x1EE78, 0x1EE78}, + {0x1EE7D, 0x1EE7D}, + {0x1EE7F, 0x1EE7F}, + {0x1EE8A, 0x1EE8A}, + {0x1EE9C, 0x1EEA0}, + {0x1EEA4, 0x1EEA4}, + {0x1EEAA, 0x1EEAA}, + {0x1EEBC, 0x1EEEF}, + {0x1EEF2, 0x1EFFF}, + {0x1F02C, 0x1F02F}, + {0x1F094, 0x1F09F}, + {0x1F0AF, 0x1F0B0}, + {0x1F0C0, 0x1F0C0}, + {0x1F0D0, 0x1F0D0}, + {0x1F0F6, 0x1F0FF}, + {0x1F1AE, 0x1F1E5}, + {0x1F203, 0x1F20F}, + {0x1F23C, 0x1F23F}, + {0x1F249, 0x1F24F}, + {0x1F252, 0x1F25F}, + {0x1F266, 0x1F2FF}, + {0x1F6D9, 0x1F6DB}, + {0x1F6ED, 0x1F6EF}, + {0x1F6FD, 0x1F6FF}, + {0x1F7DA, 0x1F7DF}, + {0x1F7EC, 0x1F7EF}, + {0x1F7F1, 0x1F7FF}, + {0x1F80C, 0x1F80F}, + {0x1F848, 0x1F84F}, + {0x1F85A, 0x1F85F}, + {0x1F888, 0x1F88F}, + {0x1F8AE, 0x1F8AF}, + {0x1F8BC, 0x1F8BF}, + {0x1F8C2, 0x1F8CF}, + {0x1F8D9, 0x1F8FF}, + {0x1FA58, 0x1FA5F}, + {0x1FA6E, 0x1FA6F}, + {0x1FA7D, 0x1FA7F}, + {0x1FA8B, 0x1FA8D}, + {0x1FAC7, 0x1FAC7}, + {0x1FAC9, 0x1FACC}, + {0x1FADD, 0x1FADE}, + {0x1FAEB, 0x1FAEE}, + {0x1FAF9, 0x1FAFF}, + {0x1FB93, 0x1FB93}, + {0x1FBFB, 0x1FFFD}, + {0x20001, 0x2A6DE}, + {0x2A6E0, 0x2A6FF}, + {0x2A701, 0x2B73E}, + {0x2B741, 0x2B81C}, + {0x2B81E, 0x2B81F}, + {0x2B821, 0x2CEAC}, + {0x2CEAE, 0x2CEAF}, + {0x2CEB1, 0x2EBDF}, + {0x2EBE1, 0x2EBEF}, + {0x2EBF1, 0x2EE5C}, + {0x2EE5E, 0x2F7FF}, + {0x2FA1E, 0x2FFFD}, + {0x30001, 0x31349}, + {0x3134B, 0x3134F}, + {0x31351, 0x323AE}, + {0x323B1, 0x33478}, + {0x3347A, 0x3FFFD}, + {0x40000, 0x4FFFD}, + {0x50000, 0x5FFFD}, + {0x60000, 0x6FFFD}, + {0x70000, 0x7FFFD}, + {0x80000, 0x8FFFD}, + {0x90000, 0x9FFFD}, + {0xA0000, 0xAFFFD}, + {0xB0000, 0xBFFFD}, + {0xC0000, 0xCFFFD}, + {0xD0000, 0xDFFFD}, + {0xE0000, 0xE0000}, + {0xE0002, 0xE001F}, + {0xE0080, 0xE00FF}, + {0xE01F0, 0xEFFFD} +}; + +/* Non-characters. */ +static const struct widechar_range widechar_nonchar_table[] = { + {0x0FDD0, 0x0FDEF}, + {0x0FFFE, 0x0FFFF}, + {0x1FFFE, 0x1FFFF}, + {0x2FFFE, 0x2FFFF}, + {0x3FFFE, 0x3FFFF}, + {0x4FFFE, 0x4FFFF}, + {0x5FFFE, 0x5FFFF}, + {0x6FFFE, 0x6FFFF}, + {0x7FFFE, 0x7FFFF}, + {0x8FFFE, 0x8FFFF}, + {0x9FFFE, 0x9FFFF}, + {0xAFFFE, 0xAFFFF}, + {0xBFFFE, 0xBFFFF}, + {0xCFFFE, 0xCFFFF}, + {0xDFFFE, 0xDFFFF}, + {0xEFFFE, 0xEFFFF}, + {0xFFFFE, 0xFFFFF}, + {0x10FFFE, 0x10FFFF} +}; + +/* Characters that were widened from width 1 to 2 in Unicode 9. */ +static const struct widechar_range widechar_widened_table[] = { + {0x0231A, 0x0231B}, + {0x023E9, 0x023EC}, + {0x023F0, 0x023F0}, + {0x023F3, 0x023F3}, + {0x025FD, 0x025FE}, + {0x02614, 0x02615}, + {0x02648, 0x02653}, + {0x0267F, 0x0267F}, + {0x02693, 0x02693}, + {0x026A1, 0x026A1}, + {0x026AA, 0x026AB}, + {0x026BD, 0x026BE}, + {0x026C4, 0x026C5}, + {0x026CE, 0x026CE}, + {0x026D4, 0x026D4}, + {0x026EA, 0x026EA}, + {0x026F2, 0x026F3}, + {0x026F5, 0x026F5}, + {0x026FA, 0x026FA}, + {0x026FD, 0x026FD}, + {0x02705, 0x02705}, + {0x0270A, 0x0270B}, + {0x02728, 0x02728}, + {0x0274C, 0x0274C}, + {0x0274E, 0x0274E}, + {0x02753, 0x02755}, + {0x02757, 0x02757}, + {0x02795, 0x02797}, + {0x027B0, 0x027B0}, + {0x027BF, 0x027BF}, + {0x02B1B, 0x02B1C}, + {0x02B50, 0x02B50}, + {0x02B55, 0x02B55}, + {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, + {0x1F18E, 0x1F18E}, + {0x1F191, 0x1F19A}, + {0x1F201, 0x1F201}, + {0x1F21A, 0x1F21A}, + {0x1F22F, 0x1F22F}, + {0x1F232, 0x1F236}, + {0x1F238, 0x1F23A}, + {0x1F250, 0x1F251}, + {0x1F300, 0x1F320}, + {0x1F32D, 0x1F335}, + {0x1F337, 0x1F37C}, + {0x1F37E, 0x1F393}, + {0x1F3A0, 0x1F3CA}, + {0x1F3CF, 0x1F3D3}, + {0x1F3E0, 0x1F3F0}, + {0x1F3F4, 0x1F3F4}, + {0x1F3F8, 0x1F43E}, + {0x1F440, 0x1F440}, + {0x1F442, 0x1F4FC}, + {0x1F4FF, 0x1F53D}, + {0x1F54B, 0x1F54E}, + {0x1F550, 0x1F567}, + {0x1F595, 0x1F596}, + {0x1F5FB, 0x1F64F}, + {0x1F680, 0x1F6C5}, + {0x1F6CC, 0x1F6CC}, + {0x1F6D0, 0x1F6D0}, + {0x1F6EB, 0x1F6EC}, + {0x1F910, 0x1F918}, + {0x1F980, 0x1F984}, + {0x1F9C0, 0x1F9C0} +}; + +static inline bool widechar_in_table(const struct widechar_range* arr, size_t len, uint32_t c) { + + size_t lo=0; + size_t hi=len; + + if(c < arr[0].lo) return(0); + if(c > arr[len-1].hi) return(0); + + while(1) { + size_t mid = ((hi-lo)/2)+lo; + if( (c >= arr[mid].lo) && (c <= arr[mid].hi)) { + return(1); + } + if(mid == lo) return(0); + + if (c < arr[mid].lo) { + hi = mid; + } else { + lo = mid; + } + } + return(0); +} + + + +/* Return the width of character c, or a special negative value. */ +int widechar_wcwidth(uint32_t c) { + if (widechar_in_table(widechar_ascii_table, widechar_ARRAY_SIZE(widechar_ascii_table), c)) + return 1; + if (widechar_in_table(widechar_private_table, widechar_ARRAY_SIZE(widechar_private_table), c)) + return widechar_private_use; + if (widechar_in_table(widechar_nonprint_table, widechar_ARRAY_SIZE(widechar_nonprint_table), c)) + return widechar_nonprint; + if (widechar_in_table(widechar_nonchar_table, widechar_ARRAY_SIZE(widechar_nonchar_table), c)) + return widechar_non_character; + if (widechar_in_table(widechar_combining_table, widechar_ARRAY_SIZE(widechar_combining_table), c)) + return widechar_combining; + if (widechar_in_table(widechar_combiningletters_table, widechar_ARRAY_SIZE(widechar_combiningletters_table), c)) + return widechar_combining; + if (widechar_in_table(widechar_doublewide_table, widechar_ARRAY_SIZE(widechar_doublewide_table), c)) + return 2; + if (widechar_in_table(widechar_ambiguous_table, widechar_ARRAY_SIZE(widechar_ambiguous_table), c)) + return widechar_ambiguous; + if (widechar_in_table(widechar_unassigned_table, widechar_ARRAY_SIZE(widechar_unassigned_table), c)) + return widechar_unassigned; + if (widechar_in_table(widechar_widened_table, widechar_ARRAY_SIZE(widechar_widened_table), c)) + return widechar_widened_in_9; + return 1; +} + +#endif // WIDECHAR_WIDTH_H diff --git a/src/common/commandoption.c b/src/common/commandoption.c index a419a7867c..626a1c06fd 100644 --- a/src/common/commandoption.c +++ b/src/common/commandoption.c @@ -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); } } diff --git a/src/detection/cpu/cpu.c b/src/detection/cpu/cpu.c index 01bdd5f964..37bd27a639 100644 --- a/src/detection/cpu/cpu.c +++ b/src/detection/cpu/cpu.c @@ -132,35 +132,7 @@ void ffCPUDetectByCpuid(FFCPUResult* cpu) #ifdef __linux__ #include "common/io/io.h" #include -#include - -#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 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"; diff --git a/src/detection/cpu/cpu_arm.h b/src/detection/cpu/cpu_arm.h index cc23d4576e..77cacbf877 100644 --- a/src/detection/cpu/cpu_arm.h +++ b/src/detection/cpu/cpu_arm.h @@ -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; } } diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 112bced88c..06145e802b 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -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; diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 79ed7a660a..d742a702cd 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -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) { diff --git a/src/detection/disk/disk.c b/src/detection/disk/disk.c index 0b43027fa0..5d52b86e7b 100644 --- a/src/detection/disk/disk.c +++ b/src/detection/disk/disk.c @@ -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); diff --git a/src/detection/disk/disk.h b/src/detection/disk/disk.h index 526de81282..f2fab87826 100644 --- a/src/detection/disk/disk.h +++ b/src/detection/disk/disk.h @@ -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); diff --git a/src/detection/disk/disk_bsd.c b/src/detection/disk/disk_bsd.c index 6a4860283c..13597fb967 100644 --- a/src/detection/disk/disk_bsd.c +++ b/src/detection/disk/disk_bsd.c @@ -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")) diff --git a/src/detection/disk/disk_haiku.cpp b/src/detection/disk/disk_haiku.cpp index 6bf2169229..25fe018b96 100644 --- a/src/detection/disk/disk_haiku.cpp +++ b/src/detection/disk/disk_haiku.cpp @@ -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; } diff --git a/src/detection/disk/disk_linux.c b/src/detection/disk/disk_linux.c index 377faf9fc0..8cb9130e91 100644 --- a/src/detection/disk/disk_linux.c +++ b/src/detection/disk/disk_linux.c @@ -10,6 +10,10 @@ #include #include +#ifdef STATX_BTIME + #include +#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)) diff --git a/src/detection/disk/disk_sunos.c b/src/detection/disk/disk_sunos.c index d52a5e9075..8272cc1ed7 100644 --- a/src/detection/disk/disk_sunos.c +++ b/src/detection/disk/disk_sunos.c @@ -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)) diff --git a/src/detection/disk/disk_windows.c b/src/detection/disk/disk_windows.c index 092a247c36..ea6766b459 100644 --- a/src/detection/disk/disk_windows.c +++ b/src/detection/disk/disk_windows.c @@ -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) diff --git a/src/detection/localip/localip.h b/src/detection/localip/localip.h index e3361cfbfe..685ff3f48f 100644 --- a/src/detection/localip/localip.h +++ b/src/detection/localip/localip.h @@ -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; diff --git a/src/detection/localip/localip_linux.c b/src/detection/localip/localip_linux.c index 962e259c09..1b5537ff6a 100644 --- a/src/detection/localip/localip_linux.c +++ b/src/detection/localip/localip_linux.c @@ -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) - { - selected = *pifa; - FF_DEBUG("Found preferred IPv6 address for interface %s", adapter->mac->ifa_name); - break; - } - else if (type == FF_IPV6_GUA && !selected) + struct ifaddrs* selected = NULL; + struct ifaddrs* secondary = NULL; + + FF_LIST_FOR_EACH(struct ifaddrs*, pifa, adapter->ipv6) { - selected = *pifa; - FF_DEBUG("Found GUA IPv6 address for interface %s", adapter->mac->ifa_name); + 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_ULA && !secondary) + if (!selected) selected = secondary; + + if (selected) + appendIpv6(options, &item->ipv6, selected); + else if (adapter->ipv6.length > 0) { - 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: diff --git a/src/detection/localip/localip_windows.c b/src/detection/localip/localip_windows.c index 2e12280c30..7c4e32a45e 100644 --- a/src/detection/localip/localip_windows.c +++ b/src/detection/localip/localip_windows.c @@ -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); diff --git a/src/detection/opengl/opengl_windows.c b/src/detection/opengl/opengl_windows.c index cc251c1885..fe82ec14ea 100644 --- a/src/detection/opengl/opengl_windows.c +++ b/src/detection/opengl/opengl_windows.c @@ -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; } diff --git a/src/detection/os/os_linux.c b/src/detection/os/os_linux.c index 376bf8d343..b2d0621dc0 100644 --- a/src/detection/os/os_linux.c +++ b/src/detection/os/os_linux.c @@ -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"); diff --git a/src/detection/terminalfont/terminalfont.c b/src/detection/terminalfont/terminalfont.c index 847788fb10..a4468b9c15 100644 --- a/src/detection/terminalfont/terminalfont.c +++ b/src/detection/terminalfont/terminalfont.c @@ -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}, - }; - - #if __APPLE__ - ffParsePropFileConfigValues("com.mitchellh.ghostty/config", 2, fontQueryToml); - #endif + // 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; + } - ffParsePropFileConfigValues("ghostty/config", 2, fontQueryToml); + 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; + } + } + } - 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); diff --git a/src/detection/wifi/wifi_apple.m b/src/detection/wifi/wifi_apple.m index 02521294f9..77b661cc47 100644 --- a/src/detection/wifi/wifi_apple.m +++ b/src/detection/wifi/wifi_apple.m @@ -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 too - return false; - } - - 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 ` returns a string like this: - // { - // BSSID : - // IPv4 : { - // ... - // } - // IPv6 : { - // ... - // } - // 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 - // ———————————————————————————————————————————————————————————————————— - // - // ———————————————————————————————————————————————————————————————————— - // ... - - { - // 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 ` 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; - } - } - } +@interface CWNetworkProfile() +@property(readonly, retain, nullable) NSArray *bssidList; +@end - return NULL; -} - -static const char* detectByCoreWlan(FFlist* result) +const char* ffDetectWifi(FFlist* result) { NSArray* interfaces = CWWiFiClient.sharedWiFiClient.interfaces; if (!interfaces) @@ -262,17 +46,19 @@ static bool getWifiInfoByIpconfig(FFstrbuf* ipconfig, const char* prefix, FFstrb 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, ""); // 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, ""); @@ -360,11 +146,6 @@ static bool getWifiInfoByIpconfig(FFstrbuf* ipconfig, const char* prefix, FFstrb 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 bool getWifiInfoByIpconfig(FFstrbuf* ipconfig, const char* prefix, FFstrb return NULL; } - -const char* ffDetectWifi(FFlist* result) -{ - if (@available(macOS 15.6, *)) - { - if (detectByWdutil(result) == NULL) - return NULL; - } - - return detectByCoreWlan(result); -} diff --git a/src/detection/zpool/zpool_linux.c b/src/detection/zpool/zpool_linux.c index d03082bd24..72ec65b552 100644 --- a/src/detection/zpool/zpool_linux.c +++ b/src/detection/zpool/zpool_linux.c @@ -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(); diff --git a/src/fastfetch.c b/src/fastfetch.c index 961af21f96..d92760d0dd 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -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(); diff --git a/src/logo/ascii/obsidianos.txt b/src/logo/ascii/obsidianos.txt index 8042b3e920..b195a1fd9b 100644 --- a/src/logo/ascii/obsidianos.txt +++ b/src/logo/ascii/obsidianos.txt @@ -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 \ No newline at end of file +$2 *+++++++# +$2#*******###$3 @ +$2#*******###$3 @ +$2#*******###$3 @ @ +$2#*******##%$3 @ +$3@@@@@@@@@ @ @ @ + @ @ @ @ @ + @ @ @ @ @ + @ @ @ @ + @ @ @ @ @ + @ @ @@@@@@@@@ + @$1#*******##%$3 + @$1 ##########%$3 + @$1 ##########%$3 + @$1 ##########% + ########% diff --git a/src/logo/ascii/starry.txt b/src/logo/ascii/starry.txt deleted file mode 100644 index 32a70050c6..0000000000 --- a/src/logo/ascii/starry.txt +++ /dev/null @@ -1,14 +0,0 @@ - */ - *,*,*( - ,,,,,,,,,,,,,,,,,,,,,,,, - ,*,*,*,*,*,*,*,*,*,*,*,* - ,,,,,,,,,,,,,,,,,,,,,,,, - *,*,*,*,*,*,*,*,*,*,*,*,*,*,* -*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, - ,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,, - ,,,,,,,,,,,,,,,,,,,,,,,,,,,* - ,*,*,*,*,*,*,*,*,*,*,*,*,*,* - ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, - (*,*,*,*,*,*,*,*,*,*,*,*,*, - ,,,,,,,,,,,,,,,, - &*,*,*#@@*,*,*, \ No newline at end of file diff --git a/src/logo/ascii/templeos.txt b/src/logo/ascii/templeos.txt new file mode 100644 index 0000000000..a9caa95049 --- /dev/null +++ b/src/logo/ascii/templeos.txt @@ -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`` + ``````` + ````` \ No newline at end of file diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 4de3cf0324..29f0540028 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -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"}, diff --git a/src/modules/disk/disk.c b/src/modules/disk/disk.c index 43283de4a5..d33cf3d6fb 100644 --- a/src/modules/disk/disk.c +++ b/src/modules/disk/disk.c @@ -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; } diff --git a/src/modules/gamepad/gamepad.c b/src/modules/gamepad/gamepad.c index 087e7dc359..327d73b15e 100644 --- a/src/modules/gamepad/gamepad.c +++ b/src/modules/gamepad/gamepad.c @@ -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 = { diff --git a/src/modules/gamepad/option.h b/src/modules/gamepad/option.h index 8640a0d7c8..b52b1dea3c 100644 --- a/src/modules/gamepad/option.h +++ b/src/modules/gamepad/option.h @@ -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; diff --git a/src/modules/keyboard/keyboard.c b/src/modules/keyboard/keyboard.c index c02c8653bf..b33c4ff4a1 100644 --- a/src/modules/keyboard/keyboard.c +++ b/src/modules/keyboard/keyboard.c @@ -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 = { diff --git a/src/modules/keyboard/option.h b/src/modules/keyboard/option.h index b65de5ceb1..6f5244a6a7 100644 --- a/src/modules/keyboard/option.h +++ b/src/modules/keyboard/option.h @@ -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"); diff --git a/src/modules/localip/localip.c b/src/modules/localip/localip.c index 6b72669407..bb479099d9 100644 --- a/src/modules/localip/localip.c +++ b/src/modules/localip/localip.c @@ -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); } diff --git a/src/modules/localip/option.h b/src/modules/localip/option.h index b809fe2fab..18205263cb 100644 --- a/src/modules/localip/option.h +++ b/src/modules/localip/option.h @@ -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; diff --git a/src/modules/mouse/mouse.c b/src/modules/mouse/mouse.c index f7afcccb09..a0e3ef69a7 100644 --- a/src/modules/mouse/mouse.c +++ b/src/modules/mouse/mouse.c @@ -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 = { diff --git a/src/modules/mouse/option.h b/src/modules/mouse/option.h index 470104d3fc..dcb5331f75 100644 --- a/src/modules/mouse/option.h +++ b/src/modules/mouse/option.h @@ -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"); diff --git a/src/modules/separator/option.h b/src/modules/separator/option.h index 92274c806b..a8b31379d3 100644 --- a/src/modules/separator/option.h +++ b/src/modules/separator/option.h @@ -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"); diff --git a/src/modules/separator/separator.c b/src/modules/separator/separator.c index 79ca19f961..bf2a5ffb31 100644 --- a/src/modules/separator/separator.c +++ b/src/modules/separator/separator.c @@ -9,27 +9,52 @@ #include -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 +#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++) + mbstate_t state = {}; + uint32_t remainLength = mbstr->length; + uint32_t result = 0; + + const char* ptr = mbstr->chars; + while (remainLength > 0 && *ptr != '\0') { - if (!isascii(mbstr->chars[i])) - { - result = 0; - break; - } + const char* lastPtr = NULL; + result += getMbrWidth(ptr, remainLength, &lastPtr, &state); + remainLength -= (uint32_t)(lastPtr - ptr); + ptr = lastPtr; } - if (__builtin_expect(result, 1)) return mbstr->length; - 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) diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index 45db80a4c4..0f9b6253f1 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -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; +} diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 7d50d6ad77..d202561007 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -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))) diff --git a/src/util/wcwidth.c b/src/util/wcwidth.c new file mode 100644 index 0000000000..38f20099e2 --- /dev/null +++ b/src/util/wcwidth.c @@ -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; + } +} diff --git a/src/util/wcwidth.h b/src/util/wcwidth.h index 4252e0f367..1f972b6a06 100644 --- a/src/util/wcwidth.h +++ b/src/util/wcwidth.h @@ -1,16 +1,16 @@ #pragma once -#include +#include #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 + +// 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 diff --git a/tests/strbuf.c b/tests/strbuf.c index f51f00cde1..496ef4b091 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -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); } {