mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 10:22:12 +02:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d99bd2e08 | |||
| 52eed51eb6 | |||
| e5237c14cb | |||
| 47d8ddad35 | |||
| 37ab01d5ee | |||
| 80f7a982e0 | |||
| cff3aed49c | |||
| 572d4ec8e9 | |||
| 5bceb29c79 | |||
| 8b153833b1 | |||
| adc92b5548 | |||
| 03e949ed30 | |||
| 6accb587af | |||
| 373e041e5e | |||
| 31bdd25a26 | |||
| 703ec597fa | |||
| 3b1314102f | |||
| d349b7f7fb | |||
| dabdb104e2 | |||
| 8d5ce7bcdb | |||
| 751568e9f3 | |||
| 430fe9fe9a | |||
| 8831c07d2b | |||
| e009bb1516 | |||
| 82e2790e1b | |||
| 64182539aa | |||
| c67fd169f8 | |||
| f58d0df336 | |||
| bd0c593871 | |||
| a032d37ad4 | |||
| a4861606b7 | |||
| 88fe34102e | |||
| 5346104ffa | |||
| 12371cdc84 | |||
| 3248afe91c | |||
| 1731ab2c5f | |||
| fcc8927917 | |||
| ccf4e2d2b5 | |||
| f2998a329d | |||
| 30365e8997 | |||
| 5b66938bf4 | |||
| 80c5600a7b | |||
| 65ce2eafed | |||
| d840c7a12d | |||
| 634e27bc42 | |||
| cc18315e84 | |||
| 83e2787b24 | |||
| ef5a9384da | |||
| 2d7e6c37ff | |||
| 92e8f23261 | |||
| e09f1d3647 | |||
| 6f01e33955 | |||
| 4b813cdf59 | |||
| 942c583c89 | |||
| 24a48c1fc0 | |||
| e2e95732e8 | |||
| d647f9e3f2 | |||
| 4895c68ca9 | |||
| f0b9800974 | |||
| be84549f4c | |||
| 0916258c87 | |||
| ad006b466c |
@@ -0,0 +1,37 @@
|
||||
name: manage pull requests
|
||||
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: manage pull request
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev rpm librpm-dev libzstd-dev
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . -j$(nproc) --target package
|
||||
|
||||
- name: run fastfetch
|
||||
run: ./fastfetch --recache --disable-linewrap false --hide-cursor false --show-errors true
|
||||
|
||||
- name: run flashfetch
|
||||
run: ./flashfetch
|
||||
|
||||
- name: run tests
|
||||
run: ctest
|
||||
|
||||
- name: perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
+28
-69
@@ -1,101 +1,60 @@
|
||||
name: Manage pushes and pull requests
|
||||
name: manage pushes
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Build, Run and Analyze fastfetch
|
||||
manage:
|
||||
name: manage push
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: write
|
||||
security-events: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'cpp' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Update and install packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libxfconf-0-dev librpm-dev libzstd-dev
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev rpm librpm-dev libzstd-dev
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
|
||||
- name: Configure
|
||||
run: cmake -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} .
|
||||
- name: configure project
|
||||
# We reuse the build binary only for the releases.
|
||||
# We set tweak version to off, because it is wrong, as git tag will happen after this step. Releases don't have a tweak, so this is ok.
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: Build
|
||||
run: cmake --build . -j$(nproc)
|
||||
- name: build project
|
||||
run: cmake --build . -j$(nproc) --target package
|
||||
|
||||
- name: Run fastfetch
|
||||
run: ./fastfetch --recache --disable-linewrap false --hide-cursor false --show-errors true
|
||||
- name: run fastfetch
|
||||
run: ./fastfetch --recache --disable-linewrap false --hide-cursor false --show-errors true
|
||||
|
||||
- name: Run flashfetch
|
||||
run: ./flashfetch
|
||||
- name: run flashfetch
|
||||
run: ./flashfetch
|
||||
|
||||
- name: Run tests
|
||||
run: ctest
|
||||
- name: run tests
|
||||
run: ctest
|
||||
|
||||
- name: Build deb package
|
||||
run: sh packaging/deb/create.sh .
|
||||
- name: perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
||||
- name: Create tarball
|
||||
if: github.event_name == 'push'
|
||||
run: tar -cvf fastfetch.tar ./fastfetch -C packaging/deb ./fastfetch.deb
|
||||
|
||||
- name: Upload tarball
|
||||
if: github.event_name == 'push'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: fastfetch.tar
|
||||
path: ./fastfetch.tar
|
||||
|
||||
deploy:
|
||||
name: Create GitHub release
|
||||
runs-on: ubuntu-latest
|
||||
needs: check
|
||||
if: github.event_name == 'push'
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Download tarball
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: fastfetch.tar
|
||||
path: ./fastfetch.tar
|
||||
|
||||
- name: Extract tarball
|
||||
run: tar --overwrite -xvf ./fastfetch.tar/fastfetch.tar
|
||||
|
||||
- name: Get fastfetch version
|
||||
- name: get fastfetch version
|
||||
id: get_version_fastfetch
|
||||
run: echo "::set-output name=release::$(./fastfetch --version)"
|
||||
run: echo "::set-output name=release::$(./fastfetch --version-raw)"
|
||||
|
||||
- name: Get latest release version
|
||||
- name: get latest release version
|
||||
id: get_version_release
|
||||
uses: pozetroninc/github-action-get-latest-release@master
|
||||
with:
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
- name: Push release
|
||||
- name: create release
|
||||
if: steps.get_version_fastfetch.outputs.release != steps.get_version_release.outputs.release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: ${{ steps.get_version_fastfetch.outputs.release }}
|
||||
commit: ${{ github.sha }}
|
||||
artifacts: ./fastfetch,./fastfetch.deb
|
||||
artifacts: ./fastfetch-*.*
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "packaging/aur"]
|
||||
path = packaging/aur
|
||||
url = https://aur.archlinux.org/fastfetch-git.git
|
||||
+200
-58
@@ -1,11 +1,20 @@
|
||||
cmake_minimum_required(VERSION 3.1.0) # Threads::Threads
|
||||
|
||||
project(fastfetch
|
||||
VERSION 1.0.0
|
||||
VERSION 1.3.3
|
||||
LANGUAGES C
|
||||
)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# This is set to off by github actions for release builds
|
||||
OPTION(SET_TWEAK "Add tweak to project version" ON)
|
||||
|
||||
# Also create test executables
|
||||
OPTION(BUILD_TESTS "Build tests" OFF)
|
||||
|
||||
OPTION(ENABLE_LIBPCI "Enable libpci" ON)
|
||||
OPTION(ENABLE_VULKAN "Enable vulkan" ON)
|
||||
@@ -19,7 +28,9 @@ OPTION(ENABLE_DCONF "Enable dconf" ON)
|
||||
OPTION(ENABLE_DBUS "Enable dbus-1" ON)
|
||||
OPTION(ENABLE_XFCONF "Enable libxfconf-0" ON)
|
||||
OPTION(ENABLE_RPM "Enable rpm" ON)
|
||||
OPTION(BUILD_TESTS "Build tests" ON)
|
||||
OPTION(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON)
|
||||
OPTION(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON)
|
||||
OPTION(ENABLE_ZLIB "Enable zlib" ON)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
@@ -28,6 +39,31 @@ endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wconversion")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-Wl,-O3")
|
||||
|
||||
# These variables are mainly here for android, which has a different root fs structure.
|
||||
if(NOT TARGET_DIR_ROOT)
|
||||
if(NOT ANDROID)
|
||||
set(TARGET_DIR_ROOT "")
|
||||
else()
|
||||
set(TARGET_DIR_ROOT "/data/data/com.termux/files/usr")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET_DIR_USR)
|
||||
if(NOT ANDROID)
|
||||
set(TARGET_DIR_USR "${TARGET_DIR_ROOT}/usr")
|
||||
else()
|
||||
set(TARGET_DIR_USR "${TARGET_DIR_ROOT}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET_DIR_HOME)
|
||||
if(NOT ANDROID)
|
||||
set(TARGET_DIR_HOME "${TARGET_DIR_ROOT}/home")
|
||||
else()
|
||||
set(TARGET_DIR_HOME "/data/data/com.termux/files/home")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(fastfetch_load_text FILENAME OUTVAR)
|
||||
file(READ "${FILENAME}" TEMP)
|
||||
string(REPLACE "\n" "\\n" TEMP "${TEMP}")
|
||||
@@ -36,6 +72,17 @@ function(fastfetch_load_text FILENAME OUTVAR)
|
||||
set("${OUTVAR}" "${TEMP}" PARENT_SCOPE)
|
||||
endfunction(fastfetch_load_text)
|
||||
|
||||
# Track commits between version bumps for output in --version
|
||||
if (SET_TWEAK AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||
execute_process(
|
||||
COMMAND git describe --tags
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
OUTPUT_VARIABLE PROJECT_VERSION_TWEAK
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(REGEX MATCH "-[0-9]+" PROJECT_VERSION_TWEAK "${PROJECT_VERSION_TWEAK}")
|
||||
endif()
|
||||
|
||||
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
|
||||
fastfetch_load_text(src/data/config.txt DATATEXT_CONFIG)
|
||||
fastfetch_load_text(src/data/modules.txt DATATEXT_MODULES)
|
||||
@@ -46,12 +93,7 @@ fastfetch_load_text(src/data/help_config.txt DATATEXT_HELP_CONFIG)
|
||||
|
||||
configure_file(src/fastfetch_config.h.in fastfetch_config.h)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# Init CMake targets.
|
||||
# Init CMake targets
|
||||
|
||||
add_library(libfastfetch STATIC
|
||||
src/util/FFstrbuf.c
|
||||
@@ -60,13 +102,21 @@ add_library(libfastfetch STATIC
|
||||
src/common/init.c
|
||||
src/common/threading.c
|
||||
src/common/io.c
|
||||
src/common/printing.c
|
||||
src/common/caching.c
|
||||
src/common/properties.c
|
||||
src/common/font.c
|
||||
src/common/processing.c
|
||||
src/common/logo.c
|
||||
src/common/format.c
|
||||
src/common/parsing.c
|
||||
src/common/settings.c
|
||||
src/common/library.c
|
||||
src/common/networking.c
|
||||
src/logo/logo.c
|
||||
src/logo/builtin.c
|
||||
src/logo/image/image.c
|
||||
src/logo/image/im7.c
|
||||
src/logo/image/im6.c
|
||||
src/detection/os.c
|
||||
src/detection/plasma.c
|
||||
src/detection/gtk.c
|
||||
@@ -117,112 +167,159 @@ add_library(libfastfetch STATIC
|
||||
)
|
||||
|
||||
if(ENABLE_LIBPCI)
|
||||
pkg_check_modules (LIBPCI libpci)
|
||||
pkg_check_modules(LIBPCI libpci)
|
||||
if(LIBPCI_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LIBPCI=1)
|
||||
else(LIBPCI_FOUND)
|
||||
else()
|
||||
message(WARNING "Package libpci not found. Building without support.")
|
||||
endif(LIBPCI_FOUND)
|
||||
endif(ENABLE_LIBPCI)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_VULKAN)
|
||||
pkg_check_modules (VULKAN vulkan)
|
||||
pkg_check_modules(VULKAN vulkan)
|
||||
if(VULKAN_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_VULKAN=1)
|
||||
else(VULKAN_FOUND)
|
||||
else()
|
||||
message(WARNING "Package vulkan not found. Building without support.")
|
||||
endif(VULKAN_FOUND)
|
||||
endif(ENABLE_VULKAN)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_WAYLAND)
|
||||
pkg_check_modules (WAYLAND wayland-client)
|
||||
if(WAYLAND_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WAYLAND=1)
|
||||
else(WAYLAND_FOUND)
|
||||
else()
|
||||
message(WARNING "Package wayland-client not found. Building without support.")
|
||||
endif(WAYLAND_FOUND)
|
||||
endif(ENABLE_WAYLAND)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_XCB_RANDR)
|
||||
pkg_check_modules (XCB_RANDR xcb-randr)
|
||||
pkg_check_modules(XCB_RANDR xcb-randr)
|
||||
if(XCB_RANDR_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XCB_RANDR=1)
|
||||
else(XCB_RANDR_FOUND)
|
||||
else()
|
||||
message(WARNING "Package xcb-randr not found. Building without support.")
|
||||
endif(XCB_RANDR_FOUND)
|
||||
endif(ENABLE_XCB_RANDR)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_XCB)
|
||||
pkg_check_modules (XCB xcb)
|
||||
if(XCB_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XCB=1)
|
||||
else(XCB_FOUND)
|
||||
else()
|
||||
message(WARNING "Package xcb not found. Building without support.")
|
||||
endif(XCB_FOUND)
|
||||
endif(ENABLE_XCB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_XRANDR)
|
||||
pkg_check_modules (XRANDR xrandr)
|
||||
pkg_check_modules(XRANDR xrandr)
|
||||
if(XRANDR_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XRANDR=1)
|
||||
else(XRANDR_FOUND)
|
||||
else()
|
||||
message(WARNING "Package xrandr not found. Building without support.")
|
||||
endif(XRANDR_FOUND)
|
||||
endif(ENABLE_XRANDR)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_X11)
|
||||
pkg_check_modules (X11 x11)
|
||||
pkg_check_modules(X11 x11)
|
||||
if(X11_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_X11=1)
|
||||
else(X11_FOUND)
|
||||
else()
|
||||
message(WARNING "Package x11 not found. Building without support.")
|
||||
endif(X11_FOUND)
|
||||
endif(ENABLE_X11)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_GIO)
|
||||
pkg_check_modules (GIO gio-2.0)
|
||||
pkg_check_modules(GIO gio-2.0)
|
||||
if(GIO_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_GIO=1)
|
||||
else(GIO_FOUND)
|
||||
else()
|
||||
message(WARNING "Package gio-2.0 not found. Building without support.")
|
||||
endif(GIO_FOUND)
|
||||
endif(ENABLE_GIO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_DCONF)
|
||||
pkg_check_modules (DCONF dconf)
|
||||
pkg_check_modules(DCONF dconf)
|
||||
if(DCONF_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_DCONF=1)
|
||||
else(DCONF_FOUND)
|
||||
else()
|
||||
message(WARNING "Package dconf not found. Building without support.")
|
||||
endif(DCONF_FOUND)
|
||||
endif(ENABLE_DCONF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_DBUS)
|
||||
pkg_check_modules (DBUS dbus-1)
|
||||
pkg_check_modules(DBUS dbus-1)
|
||||
if(DBUS_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_DBUS=1)
|
||||
else(DBUS_FOUND)
|
||||
else()
|
||||
message(WARNING "Package dbus-1 not found. Building without support.")
|
||||
endif(DBUS_FOUND)
|
||||
endif(ENABLE_DBUS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_XFCONF)
|
||||
pkg_check_modules (XFCONF libxfconf-0)
|
||||
pkg_check_modules(XFCONF libxfconf-0)
|
||||
if(XFCONF_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_XFCONF=1)
|
||||
else(XFCONF_FOUND)
|
||||
else()
|
||||
message(WARNING "Package libxfconf-0 not found. Building without support.")
|
||||
endif(XFCONF_FOUND)
|
||||
endif(ENABLE_XFCONF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_RPM)
|
||||
pkg_check_modules (RPM rpm)
|
||||
pkg_check_modules(RPM rpm)
|
||||
if(RPM_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_RPM=1)
|
||||
else(RPM_FOUND)
|
||||
else()
|
||||
message(WARNING "Package librpm not found. Building without support.")
|
||||
endif(RPM_FOUND)
|
||||
endif(ENABLE_RPM)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_IMAGEMAGICK7)
|
||||
pkg_check_modules(IMAGEMAGICK7 MagickCore-7.Q16HDRI)
|
||||
if(NOT IMAGEMAGICK7_FOUND)
|
||||
pkg_check_modules(IMAGEMAGICK7 /usr/lib/imagemagick7/pkgconfig/MagickCore-7.Q16HDRI.pc)
|
||||
endif()
|
||||
if(NOT IMAGEMAGICK7_FOUND)
|
||||
pkg_check_modules(IMAGEMAGICK7 MagickCore-7.Q16)
|
||||
endif()
|
||||
if(NOT IMAGEMAGICK7_FOUND)
|
||||
pkg_check_modules(IMAGEMAGICK7 /usr/lib/imagemagick7/pkgconfig/MagickCore-7.Q16.pc)
|
||||
endif()
|
||||
|
||||
if(IMAGEMAGICK7_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_IMAGEMAGICK7=1)
|
||||
else()
|
||||
message(WARNING "Package MagickCore-7.Q16HDRI or MagickCore-7.Q16 not found. Building without support.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_IMAGEMAGICK6)
|
||||
pkg_check_modules(IMAGEMAGICK6 MagickCore-6.Q16HDRI)
|
||||
if(NOT IMAGEMAGICK6_FOUND)
|
||||
pkg_check_modules(IMAGEMAGICK6 /usr/lib/imagemagick6/pkgconfig/MagickCore-6.Q16HDRI.pc)
|
||||
endif()
|
||||
if(NOT IMAGEMAGICK6_FOUND)
|
||||
pkg_check_modules(IMAGEMAGICK6 MagickCore-6.Q16)
|
||||
endif()
|
||||
if(NOT IMAGEMAGICK6_FOUND)
|
||||
pkg_check_modules(IMAGEMAGICK6 /usr/lib/imagemagick6/pkgconfig/MagickCore-6.Q16.pc)
|
||||
endif()
|
||||
|
||||
if(IMAGEMAGICK6_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_IMAGEMAGICK6=1)
|
||||
else()
|
||||
message(WARNING "Package MagickCore-6.Q16HDRI or MagickCore-6.Q16 not found. Building without support.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_ZLIB)
|
||||
pkg_check_modules(ZLIB zlib)
|
||||
if(ZLIB_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_ZLIB=1)
|
||||
else()
|
||||
message(WARNING "Package zlib not found. Building without support")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_include_directories(libfastfetch
|
||||
PUBLIC ${PROJECT_BINARY_DIR}
|
||||
@@ -240,6 +337,9 @@ target_include_directories(libfastfetch
|
||||
PRIVATE ${DBUS_INCLUDE_DIRS}
|
||||
PRIVATE ${XFCONF_INCLUDE_DIRS}
|
||||
PRIVATE ${RPM_INCLUDE_DIRS}
|
||||
PRIVATE ${IMAGEMAGICK7_INCLUDE_DIRS}
|
||||
PRIVATE ${IMAGEMAGICK6_INCLUDE_DIRS}
|
||||
PRIVATE ${ZLIB_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(libfastfetch
|
||||
@@ -263,7 +363,7 @@ target_link_libraries(flashfetch
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
# Testing.
|
||||
# Testing
|
||||
|
||||
if (BUILD_TESTS)
|
||||
add_executable(fastfetch-test-performance
|
||||
@@ -284,13 +384,20 @@ if (BUILD_TESTS)
|
||||
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
|
||||
endif()
|
||||
|
||||
# Installation.
|
||||
# Installation
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(
|
||||
TARGETS fastfetch
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS flashfetch
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
install(
|
||||
FILES completions/bash
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions
|
||||
@@ -306,3 +413,38 @@ install(
|
||||
FILES ./LICENSE
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/licenses/${CMAKE_PROJECT_NAME}
|
||||
)
|
||||
|
||||
# Packaging
|
||||
|
||||
set(CPACK_GENERATOR "DEB;RPM;TGZ;ZIP")
|
||||
|
||||
set(CPACK_PACKAGE_CONTACT "Linus Dierheimer <Linus@Dierheimer.de>")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Neofetch clone written in C")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "\
|
||||
fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way. \
|
||||
It is written in c to achieve much better performance.\
|
||||
")
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/LinusDierheimer")
|
||||
|
||||
set(CPACK_DEBIAN_PACKAGE_SECTION, "utils")
|
||||
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
|
||||
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "\
|
||||
libpci3, \
|
||||
libvulkan1, \
|
||||
libwayland-client0, \
|
||||
libxcb-randr0, \
|
||||
xcb, \
|
||||
libxrandr2, \
|
||||
libx11-6, \
|
||||
libdconf1, \
|
||||
libglib2.0-0, \
|
||||
libdbus-1-3, \
|
||||
libxfconf-0-3, \
|
||||
libmagickcore-6.q16hdri-6, \
|
||||
zlib1g \
|
||||
")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
|
||||
include(CPack)
|
||||
|
||||
@@ -12,7 +12,6 @@ Here i just add things that are easy to forget.
|
||||
- `libffprint`: contains the printing functions, logos, format etc
|
||||
- `fastfetch` and `flashfetch`: Executables, that initialize the config of libffprint. Fist one at runtime, second one at compile time
|
||||
- [ ] Support for printing images as ascii art logos (using imlib2 and libcaca probably)
|
||||
- [ ] Support for printing images in terminals that support it
|
||||
- [ ] Better OS output for all possible combinations of /etc/os-release variables.
|
||||
- [ ] Expose temperatures to CPU format string
|
||||
- [ ] Expose temperatures to GPU format string
|
||||
@@ -25,7 +24,6 @@ Here i just add things that are easy to forget.
|
||||
- [ ] Make CPU usage detection much faster and more accurate
|
||||
- [ ] Detect CPU usage in a common detection methode and expose it both to the cpuUsage module and the cpu format string
|
||||
- [ ] Per session caching
|
||||
- [ ] RPM packaging
|
||||
|
||||
### General
|
||||
- More presets
|
||||
|
||||
@@ -9,7 +9,7 @@ The output on my personal machine with default configurations looks like this:
|
||||
|
||||
With customization and speed being two competing goals, this project actually builds two executables.
|
||||
The main one being `fastfetch`, which can be very greatly configured via flags. These flags can be made persistent in `~/.config/fastfetch/config.conf`. To view the available options run `fastfetch --help`.
|
||||
The second executable being buildt is called `flashfetch`, which is configured at compile time to eliminate any possible overhead. Configuration of it can be very easily done in [`src/flashfetch.c`](src/flashfetch.c).
|
||||
The second executable being built is called `flashfetch`, which is configured at compile time to eliminate any possible overhead. Configuration of it can be very easily done in [`src/flashfetch.c`](src/flashfetch.c).
|
||||
At the moment the performance difference is measurable, but too small to be human recognizable. But the leap will get bigger with more and more options coming, and on slow machines this might actually make a difference.
|
||||
|
||||
There are some presets defined for fastfech in [`presets`](presets), you can can load them with `--load-config`. They may also serve as a good example for format arguments.
|
||||
@@ -28,6 +28,8 @@ The following libraries are used if present at runtime:
|
||||
* [`libwayland-client`](https://wayland.freedesktop.org/): Better resolution performance and output in wayland sessions. Supports different refresh rates per monitor.
|
||||
* [`libGIO`](https://developer.gnome.org/gio/unstable/): Needed for values that are only stored GSettings.
|
||||
* [`libDConf`](https://developer.gnome.org/dconf/unstable/): Needed for values that are only stored in DConf + Fallback for GSettings.
|
||||
* [`libmagickcore` (ImageMagick)](https://www.imagemagick.org/): Images in terminal using sixel or kitty graphics protocol.
|
||||
* [`libZ`](https://www.zlib.net/): Faster image output when using kitty graphics protocol.
|
||||
* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song.
|
||||
* [`libXFConf`](https://gitlab.xfce.org/xfce/xfconf): Needed for XFWM theme and XFCE Terminal font.
|
||||
* [`librpm`](http://rpm.org/): Needed for rpm package count.
|
||||
@@ -42,16 +44,17 @@ Title, Separator, OS, Host, Kernel, Uptime, Processes, Packages, Shell, Resoluti
|
||||
|
||||
##### Logos
|
||||
```
|
||||
Android, Arch, Arco, Artix, CachyOS, CentOS, Debian, Endeavour, Fedora, Garuda, Gentoo, KDE Neon, Linux, Manjaro, Mint, Pop!_OS, RebornOS, Ubuntu, Void, Zorin
|
||||
Android, Arch, Arco, Artix, CachyOS, CentOS, Debian, Endeavour, Fedora, Garuda, Gentoo, KDE Neon, Linux, Manjaro, Mint, NixOS, OpenSUSE, OpenSUSE Tumbleweed, OpenSUSE LEAP, Pop!_OS, RebornOS, Ubuntu, Void, Zorin
|
||||
```
|
||||
* Most of the logos have a small variant. Access it by appending _small to the logo name.
|
||||
* Some logos have an old variant. Access it by appending _old to the logo name.
|
||||
* Unknown/unsupported logos will be replaced with a generic linux logo when running fastfetch.
|
||||
* Get a list of all available logos with `fastfetch --print-logos`.
|
||||
* Printing images as logo is supported using Sixel or Kitty graphics protocol.
|
||||
|
||||
##### Package managers
|
||||
```
|
||||
Pacman, dpkg, rpm, emerge, xbps, Flatpak, Snap
|
||||
Pacman, dpkg, rpm, emerge, xbps, nix, Flatpak, Snap
|
||||
```
|
||||
|
||||
##### WM themes
|
||||
@@ -86,7 +89,7 @@ If pkg-config fails to find the headers for a library listed in [dependencies](#
|
||||
* [AUR](https://aur.archlinux.org/packages/fastfetch-git/): Packaged by me. Will install the fastfetch binary, bash completion and the presets. Git version
|
||||
* [Manjaro Repositories](https://gitlab.manjaro.org/packages/community/fastfetch): Packaged by a manjaro maintainer. Usually a bit outdated.
|
||||
* [Gentoo (Guru)](https://github.com/gentoo/guru/tree/master/app-misc/fastfetch): Packed by some other guy. May be out of date some times.
|
||||
* DEB: Run [`packaging/deb/create.sh`](packaging/deb/create.sh) from the root directory. You can give a custom build directory as an argument.
|
||||
* DEB / RPM: Run `cmake -B build && cmake --build build --target package` to build the packages in build.
|
||||
* Manually:
|
||||
* Build: Follow the [build instructions](#building).
|
||||
* Install: `sudo cmake --install build --prefix /usr/local`
|
||||
|
||||
+17
-6
@@ -122,8 +122,7 @@ __fastfetch_completion()
|
||||
"--recache"
|
||||
"--nocache"
|
||||
"--show-errors"
|
||||
"--color-logo"
|
||||
"--print-remaining-logo"
|
||||
"--logo-print-remaining"
|
||||
"--multithreading"
|
||||
"--allow-slow-operations"
|
||||
"--disable-linewrap"
|
||||
@@ -134,13 +133,23 @@ __fastfetch_completion()
|
||||
)
|
||||
|
||||
local FF_OPTIONS_STRING=(
|
||||
"--logo-type"
|
||||
"--logo-padding"
|
||||
"--logo-padding-left"
|
||||
"--logo-padding-right"
|
||||
"--logo-color-1"
|
||||
"--logo-color-2"
|
||||
"--logo-color-3"
|
||||
"--logo-color-4"
|
||||
"--logo-color-5"
|
||||
"--logo-color-6"
|
||||
"--logo-color-7"
|
||||
"--logo-color-8"
|
||||
"--logo-color-9"
|
||||
"-c"
|
||||
"--color"
|
||||
"--spacing"
|
||||
"-s"
|
||||
"--separator"
|
||||
"-x"
|
||||
"--offsetx"
|
||||
"-s"
|
||||
"--structure"
|
||||
"--set"
|
||||
"--os-format"
|
||||
@@ -223,6 +232,8 @@ __fastfetch_completion()
|
||||
"--lib-DBus"
|
||||
"--lib-XFConf"
|
||||
"--lib-RPM"
|
||||
"--lib-imagemagick"
|
||||
"--lib-z"
|
||||
"--battery-dir"
|
||||
"--load-config"
|
||||
)
|
||||
|
||||
Submodule packaging/aur deleted from 7ac9c5d132
@@ -1,13 +0,0 @@
|
||||
Package: fastfetch
|
||||
Version: <VERSION>
|
||||
Section: utils
|
||||
Priority: extra
|
||||
Architecture: amd64
|
||||
Maintainer: Linus@Dierheimer.de
|
||||
Homepage: https://github.com/LinusDierheimer/fastfetch
|
||||
Installed-Size: 410K
|
||||
Description: A fast alternative to neofetch
|
||||
fastfetch is a neofetch-like tool for fetching system information and
|
||||
displaying them in a pretty way. It is written in c to achieve much better
|
||||
performance, in return only Linux and Android are supported. It also uses
|
||||
mechanisms like multithreading and caching to finish as fast as possible.
|
||||
@@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script is intended to be run from the root of the repository.
|
||||
# If you don't want to use build/ as build directoy, or already build the elsewere, you can give the build directoy as argument.
|
||||
|
||||
BUILD_DIR="${1:-build}"
|
||||
ROOT_DIR="${2:-.}"
|
||||
PACKAGE_DIR="${BUILD_DIR}/packaging/deb/fastfetch"
|
||||
|
||||
# Create missing files
|
||||
mkdir -p "${BUILD_DIR}" || exit 1
|
||||
|
||||
if [ ! -f "${BUILD_DIR}/cmake_install.cmake" ]; then
|
||||
cmake -S "${ROOT_DIR}" -B "${BUILD_DIR}" || exit 2
|
||||
rm -f "${BUILD_DIR}/fastfetch" || exit 3 # Always rebuild the project if we reconfigured it
|
||||
fi
|
||||
|
||||
if [ ! -f "${BUILD_DIR}/fastfetch" ]; then
|
||||
cmake --build "${BUILD_DIR}" || exit 4
|
||||
fi
|
||||
|
||||
# Populate the files
|
||||
cmake --install "${BUILD_DIR}" --prefix "${PACKAGE_DIR}/usr" || exit 5
|
||||
mkdir -p "${PACKAGE_DIR}/DEBIAN" || exit 6
|
||||
sed "s/<VERSION>/$("${BUILD_DIR}/fastfetch" --version)/g" "${ROOT_DIR}/packaging/deb/control-template" > "${PACKAGE_DIR}/DEBIAN/control" || exit 7
|
||||
|
||||
# Create the package
|
||||
dpkg-deb --build "${PACKAGE_DIR}" || exit 8
|
||||
@@ -0,0 +1,203 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#define FF_CACHE_VALUE_EXTENSION "ffcv"
|
||||
#define FF_CACHE_SPLIT_EXTENSION "ffcs"
|
||||
|
||||
static void getCacheFilePath(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufAppend(buffer, &instance->state.cacheDir);
|
||||
ffStrbufAppendS(buffer, moduleName);
|
||||
|
||||
if(extension != NULL)
|
||||
{
|
||||
ffStrbufAppendC(buffer, '.');
|
||||
ffStrbufAppendS(buffer, extension);
|
||||
}
|
||||
}
|
||||
|
||||
static void readCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer)
|
||||
{
|
||||
FFstrbuf path;
|
||||
ffStrbufInitA(&path, 64);
|
||||
getCacheFilePath(instance, moduleName, extension, &path);
|
||||
ffAppendFileContent(path.chars, buffer);
|
||||
ffStrbufDestroy(&path);
|
||||
}
|
||||
|
||||
static void writeCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* content)
|
||||
{
|
||||
FFstrbuf path;
|
||||
ffStrbufInitA(&path, 64);
|
||||
getCacheFilePath(instance, moduleName, extension, &path);
|
||||
ffWriteFileContent(path.chars, content);
|
||||
ffStrbufDestroy(&path);
|
||||
}
|
||||
|
||||
void ffCacheValidate(FFinstance* instance)
|
||||
{
|
||||
if(instance->config.recache)
|
||||
return;
|
||||
|
||||
FFstrbuf content;
|
||||
ffStrbufInit(&content);
|
||||
readCacheFile(instance, "cacheversion", "ffv", &content);
|
||||
|
||||
bool isSameVersion = ffStrbufCompS(&content, FASTFETCH_PROJECT_VERSION) == 0;
|
||||
ffStrbufDestroy(&content);
|
||||
if(isSameVersion)
|
||||
return;
|
||||
|
||||
instance->config.recache = true;
|
||||
|
||||
FFstrbuf version;
|
||||
ffStrbufInitA(&version, sizeof(FASTFETCH_PROJECT_VERSION));
|
||||
ffStrbufAppendS(&version, FASTFETCH_PROJECT_VERSION);
|
||||
writeCacheFile(instance, "cacheversion", "ffv", &version);
|
||||
ffStrbufDestroy(&version);
|
||||
}
|
||||
|
||||
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache)
|
||||
{
|
||||
FFstrbuf cacheFileValue;
|
||||
ffStrbufInitA(&cacheFileValue, 64);
|
||||
getCacheFilePath(instance, moduleName, FF_CACHE_VALUE_EXTENSION, &cacheFileValue);
|
||||
cache->value = fopen(cacheFileValue.chars, "w");
|
||||
ffStrbufDestroy(&cacheFileValue);
|
||||
|
||||
FFstrbuf cacheFileSplit;
|
||||
ffStrbufInitA(&cacheFileSplit, 64);
|
||||
getCacheFilePath(instance, moduleName, FF_CACHE_SPLIT_EXTENSION, &cacheFileSplit);
|
||||
cache->split = fopen(cacheFileSplit.chars, "w");
|
||||
ffStrbufDestroy(&cacheFileSplit);
|
||||
}
|
||||
|
||||
void ffCacheClose(FFcache* cache)
|
||||
{
|
||||
if(cache->value != NULL)
|
||||
fclose(cache->value);
|
||||
|
||||
if(cache->split != NULL)
|
||||
fclose(cache->split);
|
||||
}
|
||||
|
||||
static bool printCachedValue(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat)
|
||||
{
|
||||
FFstrbuf content;
|
||||
ffStrbufInitA(&content, 512);
|
||||
readCacheFile(instance, moduleName, FF_CACHE_VALUE_EXTENSION, &content);
|
||||
|
||||
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
|
||||
|
||||
if(content.length == 0)
|
||||
return false;
|
||||
|
||||
uint8_t moduleCounter = 1;
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < content.length)
|
||||
{
|
||||
uint32_t nullByteIndex = ffStrbufNextIndexC(&content, startIndex, '\0');
|
||||
uint8_t moduleIndex = (moduleCounter == 1 && nullByteIndex == content.length) ? 0 : moduleCounter;
|
||||
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
|
||||
puts(content.chars + startIndex);
|
||||
startIndex = nullByteIndex + 1;
|
||||
++moduleCounter;
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&content);
|
||||
|
||||
return moduleCounter > 1;
|
||||
}
|
||||
|
||||
static bool printCachedFormat(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs)
|
||||
{
|
||||
FFstrbuf content;
|
||||
ffStrbufInitA(&content, 512);
|
||||
readCacheFile(instance, moduleName, FF_CACHE_SPLIT_EXTENSION, &content);
|
||||
|
||||
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
|
||||
|
||||
if(content.length == 0)
|
||||
return false;
|
||||
|
||||
uint8_t moduleCounter = 1;
|
||||
|
||||
FFformatarg* arguments = calloc(numArgs, sizeof(FFformatarg));
|
||||
uint32_t argumentCounter = 0;
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < content.length)
|
||||
{
|
||||
arguments[argumentCounter].type = FF_FORMAT_ARG_TYPE_STRING;
|
||||
arguments[argumentCounter].value = &content.chars[startIndex];
|
||||
++argumentCounter;
|
||||
|
||||
uint32_t nullByteIndex = ffStrbufNextIndexC(&content, startIndex, '\0');
|
||||
|
||||
if(argumentCounter == numArgs)
|
||||
{
|
||||
uint8_t moduleIndex = (moduleCounter == 1 && nullByteIndex == content.length) ? 0 : moduleCounter;
|
||||
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, NULL, numArgs, arguments);
|
||||
++moduleCounter;
|
||||
argumentCounter = 0;
|
||||
}
|
||||
|
||||
startIndex = nullByteIndex + 1;
|
||||
}
|
||||
|
||||
free(arguments);
|
||||
ffStrbufDestroy(&content);
|
||||
|
||||
return moduleCounter > 1;
|
||||
}
|
||||
|
||||
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs)
|
||||
{
|
||||
if(instance->config.recache)
|
||||
return false;
|
||||
|
||||
if(formatString == NULL || formatString->length == 0)
|
||||
return printCachedValue(instance, moduleName, customKeyFormat);
|
||||
else
|
||||
return printCachedFormat(instance, moduleName, customKeyFormat, formatString, numArgs);
|
||||
}
|
||||
|
||||
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
if(formatString == NULL || formatString->length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
|
||||
ffStrbufPutTo(value, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, NULL, numArgs, arguments);
|
||||
}
|
||||
|
||||
if(cache->value != NULL)
|
||||
{
|
||||
ffStrbufWriteTo(value, cache->value);
|
||||
fputc('\0', cache->value);
|
||||
}
|
||||
|
||||
if(cache->split == NULL)
|
||||
return;
|
||||
|
||||
for(uint32_t i = 0; i < numArgs; i++)
|
||||
{
|
||||
FFstrbuf buffer;
|
||||
ffStrbufInitA(&buffer, 64);
|
||||
ffFormatAppendFormatArg(&buffer, &arguments[i]);
|
||||
ffStrbufWriteTo(&buffer, cache->split);
|
||||
ffStrbufDestroy(&buffer);
|
||||
fputc('\0', cache->split);
|
||||
}
|
||||
}
|
||||
|
||||
void ffPrintAndWriteToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
FFcache cache;
|
||||
ffCacheOpenWrite(instance, moduleName, &cache);
|
||||
ffPrintAndAppendToCache(instance, moduleName, 0, customKeyFormat, &cache, value, formatString, numArgs, arguments);
|
||||
ffCacheClose(&cache);
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void fontInit(FFfont* font)
|
||||
{
|
||||
ffStrbufInit(&font->pretty);
|
||||
ffStrbufInit(&font->name);
|
||||
ffStrbufInitA(&font->size, 4);
|
||||
ffListInitA(&font->styles, sizeof(FFstrbuf), 4);
|
||||
}
|
||||
|
||||
static void fontInitPretty(FFfont* font)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->name);
|
||||
|
||||
if(font->size.length == 0 && font->styles.length == 0)
|
||||
return;
|
||||
else if(font->pretty.length == 0)
|
||||
ffStrbufAppendS(&font->pretty, "default");
|
||||
|
||||
ffStrbufAppendS(&font->pretty, " (");
|
||||
|
||||
if(font->size.length > 0)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->size);
|
||||
ffStrbufAppendS(&font->pretty, "pt");
|
||||
|
||||
if(font->styles.length > 0)
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < font->styles.length; i++)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, ffListGet(&font->styles, i));
|
||||
|
||||
if(i < font->styles.length - 1)
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
|
||||
ffStrbufAppendC(&font->pretty, ')');
|
||||
}
|
||||
|
||||
void ffFontInitQt(FFfont* font, const char* data)
|
||||
{
|
||||
fontInit(font);
|
||||
|
||||
//See https://doc.qt.io/qt-5/qfont.html#toString
|
||||
|
||||
//Family
|
||||
while(*data != ',' && *data != '\0')
|
||||
{
|
||||
ffStrbufAppendC(&font->name, *data);
|
||||
++data;
|
||||
}
|
||||
if(*data != '\0')
|
||||
++data;
|
||||
ffStrbufTrim(&font->name, ' ');
|
||||
|
||||
//Size
|
||||
while(*data != ',' && *data != '\0')
|
||||
{
|
||||
ffStrbufAppendC(&font->size, *data);
|
||||
++data;
|
||||
}
|
||||
if(*data != '\0')
|
||||
++data;
|
||||
ffStrbufTrim(&font->size, ' ');
|
||||
|
||||
#define FF_FONT_QT_SKIP_VALUE \
|
||||
while(*data != ',' && *data != '\0') \
|
||||
++data; \
|
||||
if(*data != '\0') \
|
||||
++data;
|
||||
|
||||
FF_FONT_QT_SKIP_VALUE //Pixel size
|
||||
FF_FONT_QT_SKIP_VALUE //Style hint
|
||||
FF_FONT_QT_SKIP_VALUE //Font weight
|
||||
FF_FONT_QT_SKIP_VALUE //Font style
|
||||
FF_FONT_QT_SKIP_VALUE //Underline
|
||||
FF_FONT_QT_SKIP_VALUE //Strike out
|
||||
FF_FONT_QT_SKIP_VALUE //Fixed pitch
|
||||
FF_FONT_QT_SKIP_VALUE //Always 0
|
||||
|
||||
#undef FF_FONT_QT_SKIP_VALUE
|
||||
|
||||
while(*data != '\0')
|
||||
{
|
||||
while(*data == ' ')
|
||||
++data;
|
||||
|
||||
if(*data == '\0')
|
||||
break;
|
||||
|
||||
FFstrbuf* style = ffListAdd(&font->styles);
|
||||
ffStrbufInit(style);
|
||||
while(*data != ' ' && *data != '\0')
|
||||
{
|
||||
ffStrbufAppendC(style, *data);
|
||||
++data;
|
||||
}
|
||||
}
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
|
||||
{
|
||||
while(**data == ' ' || **data == '\t' || **data == ',')
|
||||
++(*data);
|
||||
|
||||
const char* wordStart = *data;
|
||||
|
||||
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
|
||||
++(*data);
|
||||
|
||||
uint32_t wordLength = (uint32_t) (*data - wordStart);
|
||||
if(wordLength == 0)
|
||||
return;
|
||||
|
||||
if(**data == '\0' || **data == '`' || **data == '\\')
|
||||
{
|
||||
ffStrbufAppendNS(&font->size, wordLength, wordStart);
|
||||
if(ffStrbufEndsWithS(&font->size, "px"))
|
||||
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
|
||||
|
||||
double dummy;
|
||||
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
|
||||
return;
|
||||
|
||||
ffStrbufClear(&font->size);
|
||||
}
|
||||
|
||||
if(
|
||||
strncasecmp(wordStart, "Ultra", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Extra", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Semi", 4) == 0 ||
|
||||
strncasecmp(wordStart, "Demi", 4) == 0 ||
|
||||
strncasecmp(wordStart, "Normal", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Roman", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Oblique", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Italic", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Thin", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Light", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Bold", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Black", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Condensed", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Expanded", wordLength) == 0
|
||||
) {
|
||||
if(alternativeBuffer == NULL)
|
||||
{
|
||||
alternativeBuffer = ffListAdd(&font->styles);
|
||||
ffStrbufInit(alternativeBuffer);
|
||||
}
|
||||
|
||||
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
|
||||
if(
|
||||
strncasecmp(wordStart, "Ultra ", 6) == 0 ||
|
||||
strncasecmp(wordStart, "Extra ", 6) == 0 ||
|
||||
strncasecmp(wordStart, "Semi ", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Demi ", 5) == 0
|
||||
) {
|
||||
fontPangoParseWord(data, font, alternativeBuffer);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(alternativeBuffer != NULL)
|
||||
{
|
||||
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
return;
|
||||
}
|
||||
|
||||
if(font->name.length > 0)
|
||||
ffStrbufAppendC(&font->name, ' ');
|
||||
ffStrbufAppendNS(&font->name, wordLength, wordStart);
|
||||
}
|
||||
|
||||
void ffFontInitPango(FFfont* font, const char* data)
|
||||
{
|
||||
fontInit(font);
|
||||
|
||||
while(*data != '\0' && *data != '`' && *data != '\\')
|
||||
fontPangoParseWord(&data, font, NULL);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitCopy(FFfont* font, const char* name)
|
||||
{
|
||||
fontInit(font);
|
||||
ffStrbufAppendS(&font->name, name);
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontDestroy(FFfont* font)
|
||||
{
|
||||
ffStrbufDestroy(&font->pretty);
|
||||
ffStrbufDestroy(&font->name);
|
||||
ffStrbufDestroy(&font->size);
|
||||
|
||||
for(uint32_t i = 0; i < font->styles.length; i++)
|
||||
ffStrbufDestroy(ffListGet(&font->styles, i));
|
||||
ffListDestroy(&font->styles);
|
||||
}
|
||||
+2
-3
@@ -173,7 +173,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, const FFst
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
else
|
||||
{
|
||||
ffStrbufAppendS(buffer, "\033[0m");
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
--numOpenColors;
|
||||
}
|
||||
|
||||
@@ -284,6 +284,5 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, const FFst
|
||||
|
||||
ffStrbufTrimRight(buffer, ' ');
|
||||
|
||||
if(numOpenColors > 0)
|
||||
ffStrbufAppendS(buffer, "\033[0m");
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
}
|
||||
|
||||
+34
-15
@@ -58,12 +58,12 @@ static void initConfigDirs(FFstate* state)
|
||||
|
||||
FFstrbuf* systemConfigHome = ffListAdd(&state->configDirs);
|
||||
ffStrbufInitA(systemConfigHome, 64);
|
||||
ffStrbufAppendS(systemConfigHome, "/etc/xdg");
|
||||
ffStrbufAppendS(systemConfigHome, FASTFETCH_TARGET_DIR_ROOT"/etc/xdg");
|
||||
FF_ENSURE_ONLY_ONCE_IN_LIST(systemConfigHome)
|
||||
|
||||
FFstrbuf* systemConfig = ffListAdd(&state->configDirs);
|
||||
ffStrbufInitA(systemConfig, 64);
|
||||
ffStrbufAppendS(systemConfig, "/etc");
|
||||
ffStrbufAppendS(systemConfig, FASTFETCH_TARGET_DIR_ROOT"/etc");
|
||||
FF_ENSURE_ONLY_ONCE_IN_LIST(systemConfig)
|
||||
|
||||
#undef FF_ENSURE_ONLY_ONCE_IN_LIST
|
||||
@@ -92,6 +92,8 @@ static void initCacheDir(FFstate* state)
|
||||
static void initState(FFstate* state)
|
||||
{
|
||||
state->logoWidth = 0;
|
||||
state->logoHeight = 0;
|
||||
state->keysHeight = 0;
|
||||
state->passwd = getpwuid(getuid());
|
||||
uname(&state->utsname);
|
||||
sysinfo(&state->sysinfo);
|
||||
@@ -102,25 +104,25 @@ static void initState(FFstate* state)
|
||||
|
||||
static void defaultConfig(FFinstance* instance)
|
||||
{
|
||||
ffStrbufInit(&instance->config.color);
|
||||
ffStrbufInit(&instance->config.logoSource);
|
||||
instance->config.logoType = FF_LOGO_TYPE_AUTO;
|
||||
for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i)
|
||||
ffStrbufInit(&instance->config.logoColors[i]);
|
||||
instance->config.logoWidth = 65;
|
||||
instance->config.logoPaddingLeft = 0;
|
||||
instance->config.logoPaddingRight = 4;
|
||||
instance->config.logoPrintRemaining = true;
|
||||
|
||||
ffStrbufInit(&instance->config.mainColor);
|
||||
ffStrbufInit(&instance->config.separator);
|
||||
ffStrbufAppendS(&instance->config.separator, ": ");
|
||||
|
||||
instance->config.logoKeySpacing = 4;
|
||||
instance->config.offsetx = 0;
|
||||
instance->config.colorLogo = true;
|
||||
instance->config.showErrors = false;
|
||||
instance->config.recache = false;
|
||||
instance->config.cacheSave = true;
|
||||
instance->config.printRemainingLogo = true;
|
||||
instance->config.allowSlowOperations = false;
|
||||
instance->config.disableLinewrap = true;
|
||||
instance->config.hideCursor = true;
|
||||
instance->config.userLogoIsRaw = false;
|
||||
|
||||
for(uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i)
|
||||
ffStrbufInit(&instance->config.logoColors[i]);
|
||||
|
||||
ffStrbufInitA(&instance->config.osFormat, 0);
|
||||
ffStrbufInitA(&instance->config.osKey, 0);
|
||||
@@ -197,6 +199,8 @@ static void defaultConfig(FFinstance* instance)
|
||||
ffStrbufInitA(&instance->config.libDBus, 0);
|
||||
ffStrbufInitA(&instance->config.libXFConf, 0);
|
||||
ffStrbufInitA(&instance->config.librpm, 0);
|
||||
ffStrbufInitA(&instance->config.libImageMagick, 0);
|
||||
ffStrbufInitA(&instance->config.libZ, 0);
|
||||
|
||||
ffStrbufInitA(&instance->config.diskFolders, 0);
|
||||
|
||||
@@ -219,7 +223,6 @@ void ffInitInstance(FFinstance* instance)
|
||||
{
|
||||
initState(&instance->state);
|
||||
defaultConfig(instance);
|
||||
ffCacheValidate(instance);
|
||||
}
|
||||
|
||||
static void resetConsole(bool disableLinewrap, bool hideCursor)
|
||||
@@ -253,21 +256,28 @@ void ffStart(FFinstance* instance)
|
||||
sigaction(SIGTERM, &action, NULL);
|
||||
sigaction(SIGQUIT, &action, NULL);
|
||||
|
||||
//We do the cache validation here, so we can skip it if --recache is given
|
||||
ffCacheValidate(instance);
|
||||
|
||||
//reset everything to default before we start printing
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
|
||||
if(instance->config.hideCursor)
|
||||
fputs("\033[?25l", stdout);
|
||||
|
||||
if(instance->config.disableLinewrap)
|
||||
fputs("\033[?7l", stdout);
|
||||
|
||||
ffPrintLogo(instance);
|
||||
}
|
||||
|
||||
void ffFinish(FFinstance* instance)
|
||||
{
|
||||
if(instance->config.printRemainingLogo)
|
||||
ffPrintRemainingLogo(instance);
|
||||
|
||||
ffPrintRemainingLogo(instance);
|
||||
resetConsole(instance->config.disableLinewrap, instance->config.hideCursor);
|
||||
}
|
||||
|
||||
//Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
|
||||
void ffListFeatures()
|
||||
{
|
||||
fputs(
|
||||
@@ -301,6 +311,15 @@ void ffListFeatures()
|
||||
#ifdef FF_HAVE_DBUS
|
||||
"dbus\n"
|
||||
#endif
|
||||
#ifdef FF_HAVE_IMAGEMAGICK7
|
||||
"imagemagick7\n"
|
||||
#endif
|
||||
#ifdef FF_HAVE_IMAGEMAGICK6
|
||||
"imagemagick6\n"
|
||||
#endif
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
"zlib\n"
|
||||
#endif
|
||||
#ifdef FF_HAVE_XFCONF
|
||||
"xfconf\n"
|
||||
#endif
|
||||
|
||||
+66
-410
@@ -1,421 +1,52 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define FF_IO_CACHE_VALUE_EXTENSION "ffcv"
|
||||
#define FF_IO_CACHE_SPLIT_EXTENSION "ffcs"
|
||||
|
||||
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat)
|
||||
{
|
||||
ffPrintLogoLine(instance);
|
||||
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
|
||||
ffPrintColor(&instance->config.color);
|
||||
|
||||
if(customKeyFormat == NULL || customKeyFormat->length == 0)
|
||||
{
|
||||
fputs(moduleName, stdout);
|
||||
|
||||
if(moduleIndex > 0)
|
||||
printf(" %hhu", moduleIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
FFstrbuf key;
|
||||
ffStrbufInit(&key);
|
||||
ffParseFormatString(&key, customKeyFormat, NULL, 1, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_UINT8, &moduleIndex}
|
||||
});
|
||||
ffStrbufWriteTo(&key, stdout);
|
||||
ffStrbufDestroy(&key);
|
||||
}
|
||||
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
ffStrbufWriteTo(&instance->config.separator, stdout);
|
||||
}
|
||||
|
||||
void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numFormatArgs, const char* message, ...)
|
||||
{
|
||||
if(!instance->config.showErrors)
|
||||
return;
|
||||
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
|
||||
if(formatString == NULL || formatString->length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
|
||||
vprintf(message, arguments);
|
||||
puts(FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_STRBUF_CREATE(error);
|
||||
ffStrbufAppendVF(&error, message, arguments);
|
||||
|
||||
// calloc sets all to 0 and FF_FORMAT_ARG_TYPE_NULL also has value 0 so we don't need to explictly set it
|
||||
FFformatarg* nullArgs = calloc(numFormatArgs, sizeof(FFformatarg));
|
||||
|
||||
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, &error, numFormatArgs, nullArgs);
|
||||
|
||||
free(nullArgs);
|
||||
ffStrbufDestroy(&error);
|
||||
}
|
||||
|
||||
va_end(arguments);
|
||||
}
|
||||
|
||||
void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
FFstrbuf buffer;
|
||||
ffStrbufInitA(&buffer, 256);
|
||||
|
||||
ffParseFormatString(&buffer, formatString, error, numArgs, arguments);
|
||||
|
||||
if(buffer.length > 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&buffer);
|
||||
}
|
||||
|
||||
void ffGetCacheFilePath(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufAppend(buffer, &instance->state.cacheDir);
|
||||
ffStrbufAppendS(buffer, moduleName);
|
||||
|
||||
if(extension != NULL)
|
||||
{
|
||||
ffStrbufAppendC(buffer, '.');
|
||||
ffStrbufAppendS(buffer, extension);
|
||||
}
|
||||
}
|
||||
|
||||
void ffReadCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer)
|
||||
{
|
||||
FFstrbuf path;
|
||||
ffStrbufInitA(&path, 64);
|
||||
ffGetCacheFilePath(instance, moduleName, extension, &path);
|
||||
ffAppendFileContent(path.chars, buffer);
|
||||
ffStrbufDestroy(&path);
|
||||
}
|
||||
|
||||
void ffWriteCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* content)
|
||||
{
|
||||
FFstrbuf path;
|
||||
ffStrbufInitA(&path, 64);
|
||||
ffGetCacheFilePath(instance, moduleName, extension, &path);
|
||||
ffWriteFileContent(path.chars, content);
|
||||
ffStrbufDestroy(&path);
|
||||
}
|
||||
|
||||
static bool printCachedValue(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat)
|
||||
{
|
||||
FFstrbuf content;
|
||||
ffStrbufInitA(&content, 512);
|
||||
ffReadCacheFile(instance, moduleName, FF_IO_CACHE_VALUE_EXTENSION, &content);
|
||||
|
||||
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
|
||||
|
||||
if(content.length == 0)
|
||||
return false;
|
||||
|
||||
uint8_t moduleCounter = 1;
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < content.length)
|
||||
{
|
||||
uint32_t nullByteIndex = ffStrbufNextIndexC(&content, startIndex, '\0');
|
||||
uint8_t moduleIndex = (moduleCounter == 1 && nullByteIndex == content.length) ? 0 : moduleCounter;
|
||||
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
|
||||
puts(content.chars + startIndex);
|
||||
startIndex = nullByteIndex + 1;
|
||||
++moduleCounter;
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&content);
|
||||
|
||||
return moduleCounter > 1;
|
||||
}
|
||||
|
||||
static bool printCachedFormat(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs)
|
||||
{
|
||||
FFstrbuf content;
|
||||
ffStrbufInitA(&content, 512);
|
||||
ffReadCacheFile(instance, moduleName, FF_IO_CACHE_SPLIT_EXTENSION, &content);
|
||||
|
||||
ffStrbufTrimRight(&content, '\0'); //Strbuf always appends a '\0' at the end. We want the last null byte to be at the position of the length
|
||||
|
||||
if(content.length == 0)
|
||||
return false;
|
||||
|
||||
uint8_t moduleCounter = 1;
|
||||
|
||||
FFformatarg* arguments = calloc(numArgs, sizeof(FFformatarg));
|
||||
uint32_t argumentCounter = 0;
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < content.length)
|
||||
{
|
||||
arguments[argumentCounter].type = FF_FORMAT_ARG_TYPE_STRING;
|
||||
arguments[argumentCounter].value = &content.chars[startIndex];
|
||||
++argumentCounter;
|
||||
|
||||
uint32_t nullByteIndex = ffStrbufNextIndexC(&content, startIndex, '\0');
|
||||
|
||||
if(argumentCounter == numArgs)
|
||||
{
|
||||
uint8_t moduleIndex = (moduleCounter == 1 && nullByteIndex == content.length) ? 0 : moduleCounter;
|
||||
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, NULL, numArgs, arguments);
|
||||
++moduleCounter;
|
||||
argumentCounter = 0;
|
||||
}
|
||||
|
||||
startIndex = nullByteIndex + 1;
|
||||
}
|
||||
|
||||
free(arguments);
|
||||
ffStrbufDestroy(&content);
|
||||
|
||||
return moduleCounter > 1;
|
||||
}
|
||||
|
||||
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs)
|
||||
{
|
||||
if(instance->config.recache)
|
||||
return false;
|
||||
|
||||
if(formatString == NULL || formatString->length == 0)
|
||||
return printCachedValue(instance, moduleName, customKeyFormat);
|
||||
else
|
||||
return printCachedFormat(instance, moduleName, customKeyFormat, formatString, numArgs);
|
||||
}
|
||||
|
||||
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
if(formatString == NULL || formatString->length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
|
||||
ffStrbufPutTo(value, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, NULL, numArgs, arguments);
|
||||
}
|
||||
|
||||
if(cache->value != NULL)
|
||||
{
|
||||
ffStrbufWriteTo(value, cache->value);
|
||||
fputc('\0', cache->value);
|
||||
}
|
||||
|
||||
if(cache->split == NULL)
|
||||
return;
|
||||
|
||||
for(uint32_t i = 0; i < numArgs; i++)
|
||||
{
|
||||
FFstrbuf buffer;
|
||||
ffStrbufInitA(&buffer, 64);
|
||||
ffFormatAppendFormatArg(&buffer, &arguments[i]);
|
||||
ffStrbufWriteTo(&buffer, cache->split);
|
||||
ffStrbufDestroy(&buffer);
|
||||
fputc('\0', cache->split);
|
||||
}
|
||||
}
|
||||
|
||||
void ffPrintAndSaveToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
FFcache cache;
|
||||
ffCacheOpenWrite(instance, moduleName, &cache);
|
||||
ffPrintAndAppendToCache(instance, moduleName, 0, customKeyFormat, &cache, value, formatString, numArgs, arguments);
|
||||
ffCacheClose(&cache);
|
||||
}
|
||||
|
||||
void ffCacheValidate(FFinstance* instance)
|
||||
{
|
||||
FFstrbuf path;
|
||||
ffStrbufInitA(&path, 64);
|
||||
ffGetCacheFilePath(instance, "cacheversion", "ffv", &path);
|
||||
|
||||
FFstrbuf content;
|
||||
ffStrbufInit(&content);
|
||||
ffAppendFileContent(path.chars, &content);
|
||||
|
||||
if(ffStrbufCompS(&content, FASTFETCH_PROJECT_VERSION) == 0)
|
||||
{
|
||||
ffStrbufDestroy(&content);
|
||||
ffStrbufDestroy(&path);
|
||||
return;
|
||||
}
|
||||
|
||||
instance->config.recache = true;
|
||||
|
||||
FFstrbuf version;
|
||||
ffStrbufInit(&version);
|
||||
ffStrbufAppendS(&version, FASTFETCH_PROJECT_VERSION);
|
||||
ffWriteFileContent(path.chars, &version);
|
||||
ffStrbufDestroy(&version);
|
||||
|
||||
ffStrbufDestroy(&content);
|
||||
ffStrbufDestroy(&path);
|
||||
}
|
||||
|
||||
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache)
|
||||
{
|
||||
FFstrbuf cacheFileValue;
|
||||
ffStrbufInitA(&cacheFileValue, 64);
|
||||
ffGetCacheFilePath(instance, moduleName, FF_IO_CACHE_VALUE_EXTENSION, &cacheFileValue);
|
||||
cache->value = fopen(cacheFileValue.chars, "w");
|
||||
ffStrbufDestroy(&cacheFileValue);
|
||||
|
||||
FFstrbuf cacheFileSplit;
|
||||
ffStrbufInitA(&cacheFileSplit, 64);
|
||||
ffGetCacheFilePath(instance, moduleName, FF_IO_CACHE_SPLIT_EXTENSION, &cacheFileSplit);
|
||||
cache->split = fopen(cacheFileSplit.chars, "w");
|
||||
ffStrbufDestroy(&cacheFileSplit);
|
||||
}
|
||||
|
||||
void ffCacheClose(FFcache* cache)
|
||||
{
|
||||
if(cache->value != NULL)
|
||||
fclose(cache->value);
|
||||
|
||||
if(cache->split != NULL)
|
||||
fclose(cache->split);
|
||||
}
|
||||
|
||||
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
bool* searchedValues = malloc(sizeof(bool) * numQueries);
|
||||
bool allSet = true;
|
||||
for(uint32_t i = 0; i < numQueries; i++)
|
||||
{
|
||||
if((searchedValues[i] = queries[i].buffer->length == 0))
|
||||
allSet = false;
|
||||
}
|
||||
|
||||
if(allSet)
|
||||
{
|
||||
free(searchedValues);
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE* file = fopen(filename, "r");
|
||||
if(file == NULL)
|
||||
return false;
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
while (getline(&line, &len, file) != -1)
|
||||
{
|
||||
for(uint32_t i = 0; i < numQueries; i++)
|
||||
{
|
||||
if(!searchedValues[i])
|
||||
continue;
|
||||
|
||||
uint32_t currentLength = queries[i].buffer->length;
|
||||
queries[i].buffer->length = 0;
|
||||
if(!ffGetPropValue(line, queries[i].start, queries[i].buffer))
|
||||
queries[i].buffer->length = currentLength;
|
||||
}
|
||||
}
|
||||
|
||||
free(searchedValues);
|
||||
|
||||
if(line != NULL)
|
||||
free(line);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileValues(filename, 1, (FFpropquery[]){{start, buffer}});
|
||||
}
|
||||
|
||||
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
FFstrbuf absolutePath;
|
||||
ffStrbufInitA(&absolutePath, 64);
|
||||
ffStrbufAppendS(&absolutePath, instance->state.passwd->pw_dir);
|
||||
ffStrbufAppendC(&absolutePath, '/');
|
||||
ffStrbufAppendS(&absolutePath, relativeFile);
|
||||
|
||||
bool result = ffParsePropFileValues(absolutePath.chars, numQueries, queries);
|
||||
|
||||
ffStrbufDestroy(&absolutePath);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileHomeValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
|
||||
}
|
||||
|
||||
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
bool foundAFile = false;
|
||||
|
||||
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
|
||||
{
|
||||
FFstrbuf* baseDir = (FFstrbuf*) ffListGet(&instance->state.configDirs, i);
|
||||
uint32_t baseDirLength = baseDir->length;
|
||||
|
||||
if(*relativeFile != '/')
|
||||
ffStrbufAppendC(baseDir, '/');
|
||||
|
||||
ffStrbufAppendS(baseDir, relativeFile);
|
||||
|
||||
if(ffParsePropFileValues(baseDir->chars, numQueries, queries))
|
||||
foundAFile = true;
|
||||
|
||||
ffStrbufSubstrBefore(baseDir, baseDirLength);
|
||||
|
||||
bool allSet = true;
|
||||
for(uint32_t k = 0; k < numQueries; k++)
|
||||
{
|
||||
if(queries[k].buffer->length == 0)
|
||||
{
|
||||
allSet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(allSet)
|
||||
break;
|
||||
}
|
||||
|
||||
return foundAFile;
|
||||
}
|
||||
|
||||
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileConfigValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
|
||||
}
|
||||
#include <stdarg.h>
|
||||
#include <termios.h>
|
||||
|
||||
bool ffWriteFDContent(int fd, const FFstrbuf* content)
|
||||
{
|
||||
return write(fd, content->chars, content->length) != -1;
|
||||
}
|
||||
|
||||
void ffWriteFileContent(const char* fileName, const FFstrbuf* content)
|
||||
static void createSubfolders(const char* fileName)
|
||||
{
|
||||
int fd = open(fileName, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if(fd == -1)
|
||||
return;
|
||||
FFstrbuf path;
|
||||
ffStrbufInit(&path);
|
||||
|
||||
ffWriteFDContent(fd, content);
|
||||
while(*fileName != '\0')
|
||||
{
|
||||
ffStrbufAppendC(&path, *fileName);
|
||||
if(*fileName == '/')
|
||||
mkdir(path.chars, S_IRWXU | S_IRGRP | S_IROTH);
|
||||
++fileName;
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&path);
|
||||
}
|
||||
|
||||
bool ffWriteFileContent(const char* fileName, const FFstrbuf* content)
|
||||
{
|
||||
int openFlagsModes = O_WRONLY | O_CREAT | O_TRUNC;
|
||||
int openFlagsRights = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
int fd = open(fileName, openFlagsModes, openFlagsRights);
|
||||
if(fd == -1)
|
||||
{
|
||||
createSubfolders(fileName);
|
||||
fd = open(fileName, openFlagsModes, openFlagsRights);
|
||||
if(fd == -1)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = ffWriteFDContent(fd, content);
|
||||
|
||||
close(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ffAppendFDContent(int fd, FFstrbuf* buffer)
|
||||
@@ -491,15 +122,40 @@ void ffSuppressIO(bool suppress)
|
||||
dup2(suppress ? nullFile : origErr, STDERR_FILENO);
|
||||
}
|
||||
|
||||
void ffPrintColor(const FFstrbuf* colorValue)
|
||||
{
|
||||
fputs("\033[", stdout);
|
||||
ffStrbufWriteTo(colorValue, stdout);
|
||||
fputc('m', stdout);
|
||||
}
|
||||
|
||||
bool ffFileExists(const char* fileName, mode_t mode)
|
||||
{
|
||||
struct stat fileStat;
|
||||
return stat(fileName, &fileStat) == 0 && ((fileStat.st_mode & S_IFMT) == mode);
|
||||
}
|
||||
|
||||
void ffGetTerminalResponse(const char* request, char end, const char* format, ...)
|
||||
{
|
||||
struct termios oldTerm, newTerm;
|
||||
tcgetattr(STDIN_FILENO, &oldTerm);
|
||||
|
||||
newTerm = oldTerm;
|
||||
newTerm.c_lflag &= (tcflag_t) ~(ICANON | ECHO);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newTerm);
|
||||
|
||||
fputs(request, stdout);
|
||||
|
||||
char buffer[512];
|
||||
int pos = 0;
|
||||
while((size_t) pos < sizeof(buffer) - 1)
|
||||
{
|
||||
char c = (char) getc(stdin);
|
||||
if(c == '\0')
|
||||
break;
|
||||
buffer[pos++] = c;
|
||||
if(c == end)
|
||||
break;
|
||||
}
|
||||
buffer[pos] = '\0';
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldTerm);
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsscanf(buffer, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
+34
-4
@@ -2,6 +2,33 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void* libraryLoad(const char* path, int maxVersion)
|
||||
{
|
||||
void* result = dlopen(path, RTLD_LAZY);
|
||||
if(result != NULL)
|
||||
return result;
|
||||
|
||||
FFstrbuf pathbuf;
|
||||
ffStrbufInitA(&pathbuf, 64);
|
||||
ffStrbufAppendS(&pathbuf, path);
|
||||
ffStrbufAppendC(&pathbuf, '.');
|
||||
|
||||
for(int i = maxVersion; i >= 0; --i)
|
||||
{
|
||||
uint32_t originalLength = pathbuf.length;
|
||||
ffStrbufAppendF(&pathbuf, "%i", i);
|
||||
|
||||
result = dlopen(pathbuf.chars, RTLD_LAZY);
|
||||
if(result != NULL)
|
||||
break;
|
||||
|
||||
ffStrbufSubstrBefore(&pathbuf, originalLength);
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&pathbuf);
|
||||
return result;
|
||||
}
|
||||
|
||||
void* ffLibraryLoad(const FFstrbuf* userProvidedName, ...)
|
||||
{
|
||||
if(userProvidedName->length > 0)
|
||||
@@ -11,12 +38,15 @@ void* ffLibraryLoad(const FFstrbuf* userProvidedName, ...)
|
||||
va_start(defaultNames, userProvidedName);
|
||||
|
||||
void* result = NULL;
|
||||
const char* name = va_arg(defaultNames, const char*);
|
||||
|
||||
while(result == NULL && name != NULL)
|
||||
while(result == NULL)
|
||||
{
|
||||
result = dlopen(name, RTLD_LAZY);
|
||||
name = va_arg(defaultNames, const char*);
|
||||
const char* path = va_arg(defaultNames, const char*);
|
||||
if(path == NULL)
|
||||
break;
|
||||
|
||||
int maxVersion = va_arg(defaultNames, int);
|
||||
result = libraryLoad(path, maxVersion);
|
||||
}
|
||||
|
||||
va_end(defaultNames);
|
||||
|
||||
-1399
File diff suppressed because it is too large
Load Diff
+39
-328
@@ -1,8 +1,45 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#include <string.h>
|
||||
bool ffStrSet(const char* str)
|
||||
{
|
||||
if(str == NULL)
|
||||
return false;
|
||||
|
||||
void ffGetGtkPretty(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
|
||||
while(*str != '\0')
|
||||
{
|
||||
if(*str != ' ' && *str != '\t' && *str != '\n' && *str != '\r')
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch)
|
||||
{
|
||||
if(major->length > 0)
|
||||
ffStrbufAppend(buffer, major);
|
||||
else if(minor->length > 0 || patch->length > 0)
|
||||
ffStrbufAppendC(buffer, '1');
|
||||
|
||||
if(minor->length == 0 && patch->length == 0)
|
||||
return;
|
||||
|
||||
ffStrbufAppendC(buffer, '.');
|
||||
|
||||
if(minor->length > 0)
|
||||
ffStrbufAppend(buffer, minor);
|
||||
else if(patch->length > 0)
|
||||
ffStrbufAppendC(buffer, '0');
|
||||
|
||||
if(patch->length == 0)
|
||||
return;
|
||||
|
||||
ffStrbufAppendC(buffer, '.');
|
||||
|
||||
ffStrbufAppend(buffer, patch);
|
||||
}
|
||||
|
||||
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4)
|
||||
{
|
||||
if(gtk2->length > 0 && gtk3->length > 0 && gtk4->length > 0)
|
||||
{
|
||||
@@ -81,329 +118,3 @@ void ffGetGtkPretty(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3
|
||||
ffStrbufAppendS(buffer, " [GTK4]");
|
||||
}
|
||||
}
|
||||
|
||||
static void fontInit(FFfont* font)
|
||||
{
|
||||
ffStrbufInit(&font->pretty);
|
||||
ffStrbufInit(&font->name);
|
||||
ffStrbufInitA(&font->size, 4);
|
||||
ffListInitA(&font->styles, sizeof(FFstrbuf), 4);
|
||||
}
|
||||
|
||||
static void fontInitPretty(FFfont* font)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->name);
|
||||
|
||||
if(font->size.length == 0 && font->styles.length == 0)
|
||||
return;
|
||||
else if(font->pretty.length == 0)
|
||||
ffStrbufAppendS(&font->pretty, "default");
|
||||
|
||||
ffStrbufAppendS(&font->pretty, " (");
|
||||
|
||||
if(font->size.length > 0)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->size);
|
||||
ffStrbufAppendS(&font->pretty, "pt");
|
||||
|
||||
if(font->styles.length > 0)
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < font->styles.length; i++)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, ffListGet(&font->styles, i));
|
||||
|
||||
if(i < font->styles.length - 1)
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
|
||||
ffStrbufAppendC(&font->pretty, ')');
|
||||
}
|
||||
|
||||
void ffFontInitQt(FFfont* font, const char* data)
|
||||
{
|
||||
fontInit(font);
|
||||
|
||||
//See https://doc.qt.io/qt-5/qfont.html#toString
|
||||
|
||||
//Family
|
||||
while(*data != ',' && *data != '\0')
|
||||
{
|
||||
ffStrbufAppendC(&font->name, *data);
|
||||
++data;
|
||||
}
|
||||
if(*data != '\0')
|
||||
++data;
|
||||
ffStrbufTrim(&font->name, ' ');
|
||||
|
||||
//Size
|
||||
while(*data != ',' && *data != '\0')
|
||||
{
|
||||
ffStrbufAppendC(&font->size, *data);
|
||||
++data;
|
||||
}
|
||||
if(*data != '\0')
|
||||
++data;
|
||||
ffStrbufTrim(&font->size, ' ');
|
||||
|
||||
#define FF_FONT_QT_SKIP_VALUE \
|
||||
while(*data != ',' && *data != '\0') \
|
||||
++data; \
|
||||
if(*data != '\0') \
|
||||
++data;
|
||||
|
||||
FF_FONT_QT_SKIP_VALUE //Pixel size
|
||||
FF_FONT_QT_SKIP_VALUE //Style hint
|
||||
FF_FONT_QT_SKIP_VALUE //Font weight
|
||||
FF_FONT_QT_SKIP_VALUE //Font style
|
||||
FF_FONT_QT_SKIP_VALUE //Underline
|
||||
FF_FONT_QT_SKIP_VALUE //Strike out
|
||||
FF_FONT_QT_SKIP_VALUE //Fixed pitch
|
||||
FF_FONT_QT_SKIP_VALUE //Always 0
|
||||
|
||||
#undef FF_FONT_QT_SKIP_VALUE
|
||||
|
||||
while(*data != '\0')
|
||||
{
|
||||
while(*data == ' ')
|
||||
++data;
|
||||
|
||||
if(*data == '\0')
|
||||
break;
|
||||
|
||||
FFstrbuf* style = ffListAdd(&font->styles);
|
||||
ffStrbufInit(style);
|
||||
while(*data != ' ' && *data != '\0')
|
||||
{
|
||||
ffStrbufAppendC(style, *data);
|
||||
++data;
|
||||
}
|
||||
}
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
|
||||
{
|
||||
while(**data == ' ' || **data == '\t' || **data == ',')
|
||||
++(*data);
|
||||
|
||||
const char* wordStart = *data;
|
||||
|
||||
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
|
||||
++(*data);
|
||||
|
||||
uint32_t wordLength = (uint32_t) (*data - wordStart);
|
||||
if(wordLength == 0)
|
||||
return;
|
||||
|
||||
if(**data == '\0' || **data == '`' || **data == '\\')
|
||||
{
|
||||
ffStrbufAppendNS(&font->size, wordLength, wordStart);
|
||||
if(ffStrbufEndsWithS(&font->size, "px"))
|
||||
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
|
||||
|
||||
double dummy;
|
||||
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
|
||||
return;
|
||||
|
||||
ffStrbufClear(&font->size);
|
||||
}
|
||||
|
||||
if(
|
||||
strncasecmp(wordStart, "Ultra", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Extra", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Semi", 4) == 0 ||
|
||||
strncasecmp(wordStart, "Demi", 4) == 0 ||
|
||||
strncasecmp(wordStart, "Normal", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Roman", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Oblique", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Italic", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Thin", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Light", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Bold", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Black", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Condensed", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Expanded", wordLength) == 0
|
||||
) {
|
||||
if(alternativeBuffer == NULL)
|
||||
{
|
||||
alternativeBuffer = ffListAdd(&font->styles);
|
||||
ffStrbufInit(alternativeBuffer);
|
||||
}
|
||||
|
||||
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
|
||||
if(
|
||||
strncasecmp(wordStart, "Ultra ", 6) == 0 ||
|
||||
strncasecmp(wordStart, "Extra ", 6) == 0 ||
|
||||
strncasecmp(wordStart, "Semi ", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Demi ", 5) == 0
|
||||
) {
|
||||
fontPangoParseWord(data, font, alternativeBuffer);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(alternativeBuffer != NULL)
|
||||
{
|
||||
ffStrbufAppendNSExludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
return;
|
||||
}
|
||||
|
||||
if(font->name.length > 0)
|
||||
ffStrbufAppendC(&font->name, ' ');
|
||||
ffStrbufAppendNS(&font->name, wordLength, wordStart);
|
||||
}
|
||||
|
||||
void ffFontInitPango(FFfont* font, const char* data)
|
||||
{
|
||||
fontInit(font);
|
||||
|
||||
while(*data != '\0' && *data != '`' && *data != '\\')
|
||||
fontPangoParseWord(&data, font, NULL);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitCopy(FFfont* font, const char* name)
|
||||
{
|
||||
fontInit(font);
|
||||
ffStrbufAppendS(&font->name, name);
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontDestroy(FFfont* font)
|
||||
{
|
||||
ffStrbufDestroy(&font->pretty);
|
||||
ffStrbufDestroy(&font->name);
|
||||
ffStrbufDestroy(&font->size);
|
||||
|
||||
for(uint32_t i = 0; i < font->styles.length; i++)
|
||||
ffStrbufDestroy(ffListGet(&font->styles, i));
|
||||
ffListDestroy(&font->styles);
|
||||
}
|
||||
|
||||
static bool getPropValueLine(const char** line, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
if(**line == '\0')
|
||||
return false;
|
||||
|
||||
//Skip any amount of whitespace at the begin of line
|
||||
while(**line == ' ' || **line == '\t')
|
||||
++(*line);
|
||||
|
||||
while(*start != '\0')
|
||||
{
|
||||
// Any amount of whitespace in the format string matches any amount of whitespace in the line, even none
|
||||
if(*start == ' ' || *start == '\t')
|
||||
{
|
||||
while(*start == ' ' || *start == '\t')
|
||||
++start;
|
||||
|
||||
while(**line == ' ' || **line == '\t')
|
||||
++(*line);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Line doesn't match start, skip it
|
||||
if(**line != *start || **line == '\0')
|
||||
return false;
|
||||
|
||||
//Line and start match, continue testing
|
||||
++(*line);
|
||||
++start;
|
||||
}
|
||||
|
||||
char valueEnd = '\n';
|
||||
|
||||
//Allow faster parsing of XML
|
||||
if(*(*line - 1) == '>')
|
||||
valueEnd = '<';
|
||||
|
||||
//Skip any amount of whitespace at the begin of the value
|
||||
while(**line == ' ' || **line == '\t')
|
||||
++(*line);
|
||||
|
||||
//Allow faster parsing of quotet values
|
||||
if(**line == '"' || **line == '\'')
|
||||
{
|
||||
valueEnd = **line;
|
||||
++(*line);
|
||||
}
|
||||
|
||||
//Copy the value to the buffer
|
||||
while(**line != valueEnd && **line != '\n' && **line != '\0')
|
||||
{
|
||||
ffStrbufAppendC(buffer, **line);
|
||||
++(*line);
|
||||
}
|
||||
|
||||
ffStrbufTrimRight(buffer, ' ');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffGetPropValue(const char* line, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return getPropValueLine(&line, start, buffer);
|
||||
}
|
||||
|
||||
bool ffGetPropValueFromLines(const char* lines, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
while(!getPropValueLine(&lines, start, buffer))
|
||||
{
|
||||
while(*lines != '\0' && *lines != '\n')
|
||||
++lines;
|
||||
|
||||
if(*lines == '\0')
|
||||
return false;
|
||||
|
||||
//Skip '\n'
|
||||
++lines;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch)
|
||||
{
|
||||
if(major->length > 0)
|
||||
ffStrbufAppend(buffer, major);
|
||||
else if(minor->length > 0 || patch->length > 0)
|
||||
ffStrbufAppendC(buffer, '1');
|
||||
|
||||
if(minor->length == 0 && patch->length == 0)
|
||||
return;
|
||||
|
||||
ffStrbufAppendC(buffer, '.');
|
||||
|
||||
if(minor->length > 0)
|
||||
ffStrbufAppend(buffer, minor);
|
||||
else if(patch->length > 0)
|
||||
ffStrbufAppendC(buffer, '0');
|
||||
|
||||
if(patch->length == 0)
|
||||
return;
|
||||
|
||||
ffStrbufAppendC(buffer, '.');
|
||||
|
||||
ffStrbufAppend(buffer, patch);
|
||||
}
|
||||
|
||||
bool ffStrSet(const char* str)
|
||||
{
|
||||
if(str == NULL)
|
||||
return false;
|
||||
|
||||
while(*str != '\0')
|
||||
{
|
||||
if(*str != ' ' && *str != '\t' && *str != '\n' && *str != '\r')
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numFormatArgs, const char* message, ...)
|
||||
{
|
||||
if(!instance->config.showErrors)
|
||||
return;
|
||||
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
|
||||
if(formatString == NULL || formatString->length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
|
||||
vprintf(message, arguments);
|
||||
puts(FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_STRBUF_CREATE(error);
|
||||
ffStrbufAppendVF(&error, message, arguments);
|
||||
|
||||
// calloc sets all to 0 and FF_FORMAT_ARG_TYPE_NULL also has value 0 so we don't need to explictly set it
|
||||
FFformatarg* nullArgs = calloc(numFormatArgs, sizeof(FFformatarg));
|
||||
|
||||
ffPrintFormatString(instance, moduleName, moduleIndex, customKeyFormat, formatString, &error, numFormatArgs, nullArgs);
|
||||
|
||||
free(nullArgs);
|
||||
ffStrbufDestroy(&error);
|
||||
}
|
||||
|
||||
va_end(arguments);
|
||||
}
|
||||
|
||||
void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments)
|
||||
{
|
||||
FFstrbuf buffer;
|
||||
ffStrbufInitA(&buffer, 256);
|
||||
|
||||
ffParseFormatString(&buffer, formatString, error, numArgs, arguments);
|
||||
|
||||
if(buffer.length > 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, moduleName, moduleIndex, customKeyFormat);
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&buffer);
|
||||
}
|
||||
|
||||
void ffPrintColor(const FFstrbuf* colorValue)
|
||||
{
|
||||
fputs("\033[", stdout);
|
||||
ffStrbufWriteTo(colorValue, stdout);
|
||||
fputc('m', stdout);
|
||||
}
|
||||
|
||||
void ffPrintCharTimes(char c, uint32_t times)
|
||||
{
|
||||
for(uint32_t i = 0; i < times; i++)
|
||||
putchar(c);
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
static bool parsePropLinePointer(const char** line, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
if(**line == '\0')
|
||||
return false;
|
||||
|
||||
//Skip any amount of whitespace at the begin of line
|
||||
while(**line == ' ' || **line == '\t')
|
||||
++(*line);
|
||||
|
||||
while(*start != '\0')
|
||||
{
|
||||
// Any amount of whitespace in the format string matches any amount of whitespace in the line, even none
|
||||
if(*start == ' ' || *start == '\t')
|
||||
{
|
||||
while(*start == ' ' || *start == '\t')
|
||||
++start;
|
||||
|
||||
while(**line == ' ' || **line == '\t')
|
||||
++(*line);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//Line doesn't match start, skip it
|
||||
if(**line != *start || **line == '\0')
|
||||
return false;
|
||||
|
||||
//Line and start match, continue testing
|
||||
++(*line);
|
||||
++start;
|
||||
}
|
||||
|
||||
char valueEnd = '\n';
|
||||
|
||||
//Allow faster parsing of XML
|
||||
if(*(*line - 1) == '>')
|
||||
valueEnd = '<';
|
||||
|
||||
//Skip any amount of whitespace at the begin of the value
|
||||
while(**line == ' ' || **line == '\t')
|
||||
++(*line);
|
||||
|
||||
//Allow faster parsing of quotet values
|
||||
if(**line == '"' || **line == '\'')
|
||||
{
|
||||
valueEnd = **line;
|
||||
++(*line);
|
||||
}
|
||||
|
||||
//Copy the value to the buffer
|
||||
while(**line != valueEnd && **line != '\n' && **line != '\0')
|
||||
{
|
||||
ffStrbufAppendC(buffer, **line);
|
||||
++(*line);
|
||||
}
|
||||
|
||||
ffStrbufTrimRight(buffer, ' ');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return parsePropLinePointer(&line, start, buffer);
|
||||
}
|
||||
|
||||
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
while(!parsePropLinePointer(&lines, start, buffer))
|
||||
{
|
||||
while(*lines != '\0' && *lines != '\n')
|
||||
++lines;
|
||||
|
||||
if(*lines == '\0')
|
||||
return false;
|
||||
|
||||
//Skip '\n'
|
||||
++lines;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The following functions return true if the file was found, independently if start was found
|
||||
// Buffers which already contain content are not overwritten
|
||||
// The last occurence of start in the first file will be the one used
|
||||
// The *Values methods always return true, if all properties were already found before, without testing if the file exists
|
||||
|
||||
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
bool* searchedValues = malloc(sizeof(bool) * numQueries);
|
||||
bool allSet = true;
|
||||
for(uint32_t i = 0; i < numQueries; i++)
|
||||
{
|
||||
if((searchedValues[i] = queries[i].buffer->length == 0))
|
||||
allSet = false;
|
||||
}
|
||||
|
||||
if(allSet)
|
||||
{
|
||||
free(searchedValues);
|
||||
return true;
|
||||
}
|
||||
|
||||
FILE* file = fopen(filename, "r");
|
||||
if(file == NULL)
|
||||
return false;
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
while (getline(&line, &len, file) != -1)
|
||||
{
|
||||
for(uint32_t i = 0; i < numQueries; i++)
|
||||
{
|
||||
if(!searchedValues[i])
|
||||
continue;
|
||||
|
||||
uint32_t currentLength = queries[i].buffer->length;
|
||||
queries[i].buffer->length = 0;
|
||||
if(!ffParsePropLine(line, queries[i].start, queries[i].buffer))
|
||||
queries[i].buffer->length = currentLength;
|
||||
}
|
||||
}
|
||||
|
||||
free(searchedValues);
|
||||
|
||||
if(line != NULL)
|
||||
free(line);
|
||||
|
||||
fclose(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileValues(filename, 1, (FFpropquery[]){{start, buffer}});
|
||||
}
|
||||
|
||||
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
FFstrbuf absolutePath;
|
||||
ffStrbufInitA(&absolutePath, 64);
|
||||
ffStrbufAppendS(&absolutePath, instance->state.passwd->pw_dir);
|
||||
ffStrbufAppendC(&absolutePath, '/');
|
||||
ffStrbufAppendS(&absolutePath, relativeFile);
|
||||
|
||||
bool result = ffParsePropFileValues(absolutePath.chars, numQueries, queries);
|
||||
|
||||
ffStrbufDestroy(&absolutePath);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileHomeValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
|
||||
}
|
||||
|
||||
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries)
|
||||
{
|
||||
bool foundAFile = false;
|
||||
|
||||
for(uint32_t i = 0; i < instance->state.configDirs.length; i++)
|
||||
{
|
||||
FFstrbuf* baseDir = (FFstrbuf*) ffListGet(&instance->state.configDirs, i);
|
||||
uint32_t baseDirLength = baseDir->length;
|
||||
|
||||
if(*relativeFile != '/')
|
||||
ffStrbufAppendC(baseDir, '/');
|
||||
|
||||
ffStrbufAppendS(baseDir, relativeFile);
|
||||
|
||||
if(ffParsePropFileValues(baseDir->chars, numQueries, queries))
|
||||
foundAFile = true;
|
||||
|
||||
ffStrbufSubstrBefore(baseDir, baseDirLength);
|
||||
|
||||
bool allSet = true;
|
||||
for(uint32_t k = 0; k < numQueries; k++)
|
||||
{
|
||||
if(queries[k].buffer->length == 0)
|
||||
{
|
||||
allSet = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(allSet)
|
||||
break;
|
||||
}
|
||||
|
||||
return foundAFile;
|
||||
}
|
||||
|
||||
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer)
|
||||
{
|
||||
return ffParsePropFileConfigValues(instance, relativeFile, 1, (FFpropquery[]){{start, buffer}});
|
||||
}
|
||||
@@ -80,7 +80,7 @@ typedef struct GSettingsData
|
||||
|
||||
static const GSettingsData* getGSettingsData(FFinstance* instance)
|
||||
{
|
||||
FF_LIBRARY_DATA_LOAD_INIT(GSettingsData, instance->config.libGIO, "libgio-2.0.so", "libgio-2.0.so.0");
|
||||
FF_LIBRARY_DATA_LOAD_INIT(GSettingsData, instance->config.libGIO, "libgio-2.0.so", 1);
|
||||
|
||||
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_schema_source_lookup)
|
||||
FF_LIBRARY_DATA_LOAD_SYMBOL(g_settings_schema_has_key)
|
||||
@@ -152,7 +152,7 @@ typedef struct DConfData
|
||||
|
||||
static const DConfData* getDConfData(FFinstance* instance)
|
||||
{
|
||||
FF_LIBRARY_DATA_LOAD_INIT(DConfData, instance->config.libDConf, "libdconf.so", "libdconf.so.1");
|
||||
FF_LIBRARY_DATA_LOAD_INIT(DConfData, instance->config.libDConf, "libdconf.so", 2);
|
||||
|
||||
FF_LIBRARY_DATA_LOAD_SYMBOL(dconf_client_read_full)
|
||||
FF_LIBRARY_DATA_LOAD_SYMBOL(dconf_client_new)
|
||||
@@ -222,7 +222,7 @@ typedef struct XFConfData
|
||||
|
||||
static const XFConfData* getXFConfData(FFinstance* instance)
|
||||
{
|
||||
FF_LIBRARY_DATA_LOAD_INIT(XFConfData, instance->config.libXFConf, "libxfconf-0.so", "libxfconf-0.so.3");
|
||||
FF_LIBRARY_DATA_LOAD_INIT(XFConfData, instance->config.libXFConf, "libxfconf-0.so", 4);
|
||||
|
||||
FF_LIBRARY_DATA_LOAD_SYMBOL(xfconf_channel_get)
|
||||
FF_LIBRARY_DATA_LOAD_SYMBOL(xfconf_channel_has_property)
|
||||
|
||||
+72
-64
@@ -27,38 +27,17 @@
|
||||
# Get the default structure with "fastfetch --print-structure".
|
||||
#--structure $"FASTFETCH_DATATEXT_STRUCTURE$"
|
||||
|
||||
# Logo option:
|
||||
# Sets the logo to use.
|
||||
# List available logos with "fastfetch --list-logos".
|
||||
# Print available logos with "fastfetch --print-logos".
|
||||
# Must be the name of an available logo or a path to a text file containing a custom logo.
|
||||
# Default is the current distribution.
|
||||
#--logo arch
|
||||
# Multithreading option:
|
||||
# Sets if fastfetch should use multiple threads to detect the values.
|
||||
# Must be true or false.
|
||||
# Default is true.
|
||||
#--multithreading true
|
||||
|
||||
# Color option:
|
||||
# Sets the color of the keys.
|
||||
# Must be linux console color codes or the name of a color.
|
||||
# Default is the primary color of the logo.
|
||||
# Use "fastfetch --help color" to learn more and see examples.
|
||||
#--color magenta
|
||||
|
||||
# Spacing option:
|
||||
# Sets the amount of whitespace between the logo and keys.
|
||||
# Must be an positive integer.
|
||||
# Default is 4.
|
||||
#--spacing 4
|
||||
|
||||
# Separator option:
|
||||
# Sets the string placed between a key and its value.
|
||||
# Can be any string.
|
||||
# Default is ": ".
|
||||
#--separator ": "
|
||||
|
||||
# Offset option:
|
||||
# Sets the amount of whitespace before the logo. Can be negative to cut the logo.
|
||||
# Must be an integer.
|
||||
# Default is 0.
|
||||
#--offsetx 0
|
||||
# Slow operations option:
|
||||
# Sets if fastfetch is allowed to use known slow operations to detect more / better values.
|
||||
# Must be true or false.
|
||||
# Default is false.
|
||||
#--allow-slow-operations false
|
||||
|
||||
# Linewrap option:
|
||||
# Sets if fastfetch should disable linewrap during the run.
|
||||
@@ -72,35 +51,25 @@
|
||||
# Default is true.
|
||||
#--hide-cursor true
|
||||
|
||||
# Remaing logo option:
|
||||
# Sets if the remaining logo should be printed, if it is higher than the information printed.
|
||||
# Must be true or false.
|
||||
# Default is true.
|
||||
#--print-remaining-logo true
|
||||
# Logo option:
|
||||
# Sets the logo to use.
|
||||
# List available logos with "fastfetch --list-logos".
|
||||
# Print available logos with "fastfetch --print-logos".
|
||||
# Must be the name of an available logo or a path to a text file containing a custom logo.
|
||||
# Default is the current distribution.
|
||||
#--logo arch
|
||||
|
||||
# Multithreading option:
|
||||
# Sets if fastfetch should use multiple threads to detect the values.
|
||||
# Must be true or false.
|
||||
# Default is true.
|
||||
#--multithreading true
|
||||
# Logo type option:
|
||||
# Sets the logo type to use.
|
||||
# Must be auto, builtin, file, raw, sixel or kitty.
|
||||
# Default is auto.
|
||||
#--logo-type auto
|
||||
|
||||
# Slow operations option:
|
||||
# Sets if fastfetch is allowed to use known slow operations to detect more / better values.
|
||||
# Must be true or false.
|
||||
# Default is false.
|
||||
#--allow-slow-operations false
|
||||
|
||||
# Color logo option:
|
||||
# Sets if the logo should be colored.
|
||||
# Must be true or false.
|
||||
# Default is true.
|
||||
#--color-logo true
|
||||
|
||||
# Separator string option:
|
||||
# Sets the string printed by the "separator" module (usually between title and rest of output)
|
||||
# Must be any string. It is repated / cut to fit perfectly.
|
||||
# Default is "-"
|
||||
#--separator-string -
|
||||
# Logo width option:
|
||||
# Sets the width of the logos (in characters) if the logo is an image.
|
||||
# Must be a positive integer.
|
||||
# Default is 65.
|
||||
#--logo-width 65
|
||||
|
||||
# Logo color options:
|
||||
# Overwrite a color in the logo. Also works for user provided logos.
|
||||
@@ -109,16 +78,53 @@
|
||||
# Default is the one specified by the logo.
|
||||
# Use "fastfetch --help color" to learn more and see examples.
|
||||
# Valid index range is [1-9].
|
||||
#--color-1 red
|
||||
#--color-2 32
|
||||
#--logo-color-1 red
|
||||
#--logo-color-2 32
|
||||
# [...]
|
||||
#--color-9 yellow
|
||||
#--logo-color-9 yellow
|
||||
|
||||
# User logo raw option:
|
||||
# Sets if color replacements should be performed on the user provided logo.
|
||||
# Logo padding option:
|
||||
# Adds a padding to the left and the right side of the logo.
|
||||
# Must be a positive integer.
|
||||
# Default is 0.
|
||||
#--logo-padding 0
|
||||
|
||||
# Logo padding left option:
|
||||
# Adds a padding to the left side of the logo.
|
||||
# Must be a positive integer.
|
||||
# Default is 0.
|
||||
#--logo-padding-left 0
|
||||
|
||||
# Logo padding right option:
|
||||
# Adds a padding to the right side of the logo.
|
||||
# Must be a positive integer.
|
||||
# Default is 0.
|
||||
#--logo-padding-right 0
|
||||
|
||||
# Logo print remaining option:
|
||||
# Sets if the remaining logo should be printed, it is has more lines than modules to show.
|
||||
# Must be true or false.
|
||||
# Default is true.
|
||||
#--color-raw true
|
||||
#--logo-print-remaining true
|
||||
|
||||
# Color option:
|
||||
# Sets the color of the keys.
|
||||
# Must be linux console color codes or the name of a color.
|
||||
# Default is the primary color of the logo.
|
||||
# Use "fastfetch --help color" to learn more and see examples.
|
||||
#--color magenta
|
||||
|
||||
# Separator option:
|
||||
# Sets the string placed between a key and its value.
|
||||
# Can be any string.
|
||||
# Default is ": ".
|
||||
#--separator ": "
|
||||
|
||||
# Separator string option:
|
||||
# Sets the string printed by the "separator" module (usually between title and rest of output)
|
||||
# Must be any string. It is repated / cut to fit perfectly.
|
||||
# Default is "-"
|
||||
#--separator-string -
|
||||
|
||||
# Public IP timeout option:
|
||||
# Sets the time to wait for the public ip server to respond.
|
||||
@@ -222,3 +228,5 @@
|
||||
#--lib-DBus /usr/lib/libdbus-1.so
|
||||
#--lib-XFConf /usr/lib/libxfconf-0.so
|
||||
#--lib-rpm /usr/lib/librpm.so
|
||||
#--lib-imagemagick /usr/lib/libMagickCore-7.Q16HDRI.so
|
||||
#--lib-z /usr/lib/libz.so
|
||||
|
||||
+38
-29
@@ -1,39 +1,46 @@
|
||||
Usage: fastfetch <options>
|
||||
|
||||
Informative options:
|
||||
-h, --help: shows this message and exits
|
||||
-h <command>, --help <command>: shows help for a specific command and exits
|
||||
-v --version: prints the version of fastfetch and exits
|
||||
--list-logos: list available logos and exits
|
||||
--list-modules: lists available modules and exits
|
||||
--list-presets: list presets fastfetch knows about and exits. They can be loaded with --load-config. (+)
|
||||
--list-features: list the supported features fastfetch was compiled with and exits. Mainly for development.
|
||||
--print-logos: show available logos and exits
|
||||
--print-config: prints the default config and exits
|
||||
--print-structure: prints the default stucture and exits
|
||||
-h,--help: shows this message and exits
|
||||
-h,--help <command>: shows help for a specific command and exits
|
||||
-v,--version: prints the version of fastfetch and exits
|
||||
--list-logos: list available logos and exits
|
||||
--list-modules: lists available modules and exits
|
||||
--list-presets: list presets fastfetch knows about and exits. They can be loaded with --load-config. (+)
|
||||
--list-features: list the supported features fastfetch was compiled with and exits. Mainly for development.
|
||||
--print-logos: show available logos and exits
|
||||
--print-config: prints the default config and exits
|
||||
--print-structure: prints the default stucture and exits
|
||||
|
||||
General options:
|
||||
--structure <structure>: sets the structure of the fetch. Must be a colon separated list of keys. Use "fastfetch --list-modules" to see the ones available.
|
||||
--set <key=value>: hard set the value of a key
|
||||
-c <color>, --color <color>: sets the color of the keys. Must be a linux console color code or the name of a color (+)
|
||||
--color-[1-9] <color>: overwrites a color of the logo. Must be a linux console color code or the name of a color
|
||||
--spacing <width>: sets the distance between logo and text
|
||||
-s <str>, --separator <str>: sets the separator between key and value. Default is a colon with a space
|
||||
-x <offset>, --offsetx <offset>: sets the x offset. Can be negative to cut the logo, but no more than logo width.
|
||||
--show-errors <?value>: print occuring errors
|
||||
-r <?value> --recache <?value>: generate new cached values
|
||||
--nocache <?value>: don't use cached values, but also don't overwrite existing ones
|
||||
--print-remaining-logo <?value>: print the remaining logo, if it is higher than the number of lines shown
|
||||
--multithreading <?value>: use multiple threads to detect values
|
||||
--load-config <file>: load a config file (+)
|
||||
--allow-slow-operations <?value>: Allow operations that are usually very slow for more detailed output
|
||||
--disable-linewrap <?value>: Disable linewrap during the run
|
||||
--hide-cursor <?value>: Hide the cursor during the run
|
||||
--logo-raw <?value>: Print a custom logo as is, without any color replacements
|
||||
-r,--recache <?value>: generate new cached values
|
||||
--nocache <?value>: don't use cached values, but also don't overwrite existing ones
|
||||
--load-config <file>: load a config file or a preset (+)
|
||||
--multithreading <?value>: use multiple threads to detect values
|
||||
--allow-slow-operations <?value>: allow operations that are usually very slow for more detailed output
|
||||
|
||||
Logo options:
|
||||
-l <name>, --logo <name>: sets the shown logo. Also changes the main color accordingly. This will also load file contents as logo if the given argument is a valid path.
|
||||
--color-logo <?value>: if set to false, the logo will be black / white
|
||||
-l,--logo <logo>: set the logo to use. The type is specified by --logo-type. If default: the name of a builtin logo or a path to a file
|
||||
--logo-type <type>: set the type of the logo given. Must be auto, builtin, file, raw, sixel or kitty.
|
||||
--logo-width <width>: set the width of the logo (in characters), if it is an image
|
||||
--logo-color-[1-9] <color>: overwrite a color in the logo
|
||||
--logo-padding <padding>: set the padding on the left and the right of the logo
|
||||
--logo-padding-left <padding>: set the padding on the left of the logo
|
||||
--logo-padding-right <padding>: set the padding on the right of the logo
|
||||
--logo-print-remaining <?value>: weather to print the remaining logo, if it has more lines than modules to display
|
||||
--sixel <file>: short for --logo-type sixel --logo <file>
|
||||
--kitty <file>: short for --logo-type kitty --logo <file>
|
||||
--file <file>: short for --logo-type file --logo <file>
|
||||
--raw <file>: short for --logo-type raw --logo <file>
|
||||
|
||||
Display options:
|
||||
-s,--structure <structure>: sets the structure of the fetch. Must be a colon separated list of keys. Use "fastfetch --list-modules" to see the ones available.
|
||||
-c,--color <color>: sets the color of the keys. Must be a linux console color code or the name of a color (+)
|
||||
--separator <str>: sets the separator between key and value. Default is a colon with a space
|
||||
--set <key=value>: hard set the value of a key
|
||||
--show-errors <?value>: print occuring errors
|
||||
--disable-linewrap <?value>: weather to disable linewrap during the run
|
||||
--hide-cursor <?value>: weather to hide the cursor during the run
|
||||
|
||||
Format options: Provide the format string for custom output. Use fastfetch --help *-format for specific help.
|
||||
--os-format <format>
|
||||
@@ -114,6 +121,8 @@ Library options: Set the path of a library to load
|
||||
--lib-DBus <path>
|
||||
--lib-XFConf <path>
|
||||
--lib-RPM <path>
|
||||
--lib-imagemagick <path>
|
||||
--lib-z <path>
|
||||
|
||||
Module specific options:
|
||||
--separator-string <str>: Set the string printed by the separator module
|
||||
|
||||
@@ -78,7 +78,7 @@ void ffdsConnectWayland(const FFinstance* instance, FFDisplayServerResult* resul
|
||||
if(getenv("XDG_RUNTIME_DIR") == NULL)
|
||||
return;
|
||||
|
||||
FF_LIBRARY_LOAD(wayland, instance->config.libWayland, , "libwayland-client.so", "libwayland-client.so.0")
|
||||
FF_LIBRARY_LOAD(wayland, instance->config.libWayland, , "libwayland-client.so", 1)
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_connect,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_dispatch,)
|
||||
|
||||
@@ -98,7 +98,7 @@ static void getKDE(FFDisplayServerResult* result)
|
||||
{
|
||||
ffStrbufSetS(&result->deProcessName, "plasmashell");
|
||||
ffStrbufSetS(&result->dePrettyName, "KDE Plasma");
|
||||
ffParsePropFile("/usr/share/xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion);
|
||||
applyBetterWM(result, getenv("KDEWM"));
|
||||
}
|
||||
|
||||
@@ -106,14 +106,14 @@ static void getGnome(FFDisplayServerResult* result)
|
||||
{
|
||||
ffStrbufSetS(&result->deProcessName, "gnome-shell");
|
||||
ffStrbufSetS(&result->dePrettyName, "GNOME");
|
||||
ffParsePropFile("/usr/share/gnome-shell/org.gnome.Extensions", "version :", &result->deVersion);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/gnome-shell/org.gnome.Extensions", "version :", &result->deVersion);
|
||||
}
|
||||
|
||||
static void getCinnamon(FFDisplayServerResult* result)
|
||||
{
|
||||
ffStrbufSetS(&result->deProcessName, "cinnamon");
|
||||
ffStrbufSetS(&result->dePrettyName, "Cinnamon");
|
||||
ffParsePropFile("/usr/share/applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", &result->deVersion);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", &result->deVersion);
|
||||
}
|
||||
|
||||
static void getMate(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
@@ -130,7 +130,7 @@ static void getMate(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
FFstrbuf micro;
|
||||
ffStrbufInit(µ);
|
||||
|
||||
ffParsePropFileValues("/usr/share/mate-about/mate-version.xml", 3, (FFpropquery[]) {
|
||||
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR"/share/mate-about/mate-version.xml", 3, (FFpropquery[]) {
|
||||
{"<platform>", &major},
|
||||
{"<minor>", &minor},
|
||||
{"<micro>", µ}
|
||||
@@ -159,7 +159,7 @@ static void getXFCE4(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
{
|
||||
ffStrbufSetS(&result->deProcessName, "xfce4-session");
|
||||
ffStrbufSetS(&result->dePrettyName, "Xfce4");
|
||||
ffParsePropFile("/usr/share/gtk-doc/html/libxfce4ui/index.html", "<div><p class=\"releaseinfo\">Version", &result->deVersion);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/gtk-doc/html/libxfce4ui/index.html", "<div><p class=\"releaseinfo\">Version", &result->deVersion);
|
||||
|
||||
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
|
||||
{
|
||||
@@ -180,12 +180,12 @@ static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
{
|
||||
ffStrbufSetS(&result->deProcessName, "lxqt-session");
|
||||
ffStrbufSetS(&result->dePrettyName, "LXQt");
|
||||
ffParsePropFile("/usr/lib/pkgconfig/lxqt.pc", "Version:", &result->deVersion);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/lib/pkgconfig/lxqt.pc", "Version:", &result->deVersion);
|
||||
|
||||
if(result->deVersion.length == 0)
|
||||
ffParsePropFile("/usr/share/cmake/lxqt/lxqt-config.cmake", "set ( LXQT_VERSION", &result->deVersion);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/cmake/lxqt/lxqt-config.cmake", "set ( LXQT_VERSION", &result->deVersion);
|
||||
if(result->deVersion.length == 0)
|
||||
ffParsePropFile("/usr/share/cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", &result->deVersion);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/cmake/lxqt/lxqt-config-version.cmake", "set ( PACKAGE_VERSION", &result->deVersion);
|
||||
|
||||
if(result->deVersion.length == 0 && instance->config.allowSlowOperations)
|
||||
{
|
||||
@@ -197,7 +197,7 @@ static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
});
|
||||
|
||||
result->deVersion.length = 0; //don't set '\0' byte
|
||||
ffGetPropValueFromLines(result->deVersion.chars , "liblxqt", &result->deVersion);
|
||||
ffParsePropLines(result->deVersion.chars , "liblxqt", &result->deVersion);
|
||||
}
|
||||
|
||||
FFstrbuf wmProcessNameBuffer;
|
||||
@@ -289,13 +289,13 @@ static void getWMProtocolNameFromEnv(FFDisplayServerResult* result)
|
||||
|
||||
static void getFromProcDir(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
{
|
||||
DIR* proc = opendir("/proc");
|
||||
DIR* proc = opendir(FASTFETCH_TARGET_DIR_ROOT"/proc");
|
||||
if(proc == NULL)
|
||||
return;
|
||||
|
||||
FFstrbuf procPath;
|
||||
ffStrbufInitA(&procPath, 64);
|
||||
ffStrbufAppendS(&procPath, "/proc/");
|
||||
ffStrbufAppendS(&procPath, FASTFETCH_TARGET_DIR_ROOT"/proc/");
|
||||
|
||||
uint32_t procPathLength = procPath.length;
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connect
|
||||
|
||||
void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(xcb, instance->config.libXcb, , "libxcb.so", "libxcb.so.1")
|
||||
FF_LIBRARY_LOAD(xcb, instance->config.libXcb, , "libxcb.so", 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_connect,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_get_setup,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(xcb, xcb_setup_roots_iterator,)
|
||||
@@ -324,7 +324,7 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen)
|
||||
|
||||
void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(xcbRandr, instance->config.libXcbRandr, , "libxcb-randr.so", "libxcb-randr.so.0")
|
||||
FF_LIBRARY_LOAD(xcbRandr, instance->config.libXcbRandr, , "libxcb-randr.so", 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_connect,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_get_setup,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(xcbRandr, xcb_setup_roots_iterator,)
|
||||
|
||||
@@ -53,7 +53,7 @@ static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDispl
|
||||
|
||||
void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(x11, instance->config.libX11, , "libX11.so", "libX11.so.6", "libX11-xcb.so", "libX11-xcb.so.1")
|
||||
FF_LIBRARY_LOAD(x11, instance->config.libX11, , "libX11.so", 7, "libX11-xcb.so", 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL(x11, XOpenDisplay,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(x11, XCloseDisplay,)
|
||||
|
||||
@@ -257,7 +257,7 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen)
|
||||
|
||||
void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(xrandr, instance->config.libXrandr, , "libXrandr.so", "libXrandr.so.2")
|
||||
FF_LIBRARY_LOAD(xrandr, instance->config.libXrandr, , "libXrandr.so", 3)
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL(xrandr, XOpenDisplay,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(xrandr, XCloseDisplay,)
|
||||
|
||||
+111
-62
@@ -53,20 +53,25 @@ static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data)
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_ARRAY)
|
||||
if(argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY)
|
||||
return false;
|
||||
|
||||
DBusMessageIter arrayIter;
|
||||
data->ffdbus_message_iter_recurse(iter, &arrayIter);
|
||||
DBusMessageIter subIter;
|
||||
data->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
|
||||
if(argType == DBUS_TYPE_VARIANT)
|
||||
return getValue(&subIter, result, data);
|
||||
|
||||
//At this point we have an array
|
||||
|
||||
bool foundAValue = false;
|
||||
|
||||
while(true)
|
||||
{
|
||||
if((foundAValue = getValue(&arrayIter, result, data)))
|
||||
if((foundAValue = getValue(&subIter, result, data)))
|
||||
ffStrbufAppendS(result, ", ");
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(arrayIter);
|
||||
FF_DBUS_ITER_CONTINUE(subIter);
|
||||
}
|
||||
|
||||
if(foundAValue)
|
||||
@@ -75,51 +80,90 @@ static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data)
|
||||
return foundAValue;
|
||||
}
|
||||
|
||||
static bool detectSong(const char* player, FFMediaResult* result, DBusData* data)
|
||||
static DBusMessage* getReply(DBusMessage* request, DBusData* data)
|
||||
{
|
||||
DBusMessage* message = data->ffdbus_message_new_method_call(player, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get");
|
||||
DBusPendingCall* pendingCall = NULL;
|
||||
dbus_bool_t succesfull = data->ffdbus_connection_send_with_reply(data->connection, request, &pendingCall, DBUS_TIMEOUT_USE_DEFAULT);
|
||||
data->ffdbus_message_unref(request);
|
||||
if(!succesfull || pendingCall == NULL)
|
||||
return NULL;
|
||||
|
||||
data->ffdbus_connection_flush(data->connection);
|
||||
data->ffdbus_pending_call_block(pendingCall);
|
||||
|
||||
DBusMessage* reply = data->ffdbus_pending_call_steal_reply(pendingCall);
|
||||
data->ffdbus_pending_call_unref(pendingCall);
|
||||
return reply;
|
||||
}
|
||||
|
||||
static DBusMessage* getProperty(const char* busName, const char* objectPath, const char* interface, const char* property, DBusData* data)
|
||||
{
|
||||
DBusMessage* message = data->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get");
|
||||
if(message == NULL)
|
||||
return false;
|
||||
return NULL;
|
||||
|
||||
DBusMessageIter requestIterator;
|
||||
data->ffdbus_message_iter_init_append(message, &requestIterator);
|
||||
|
||||
const char* arg1 = "org.mpris.MediaPlayer2.Player";
|
||||
if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &arg1))
|
||||
if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &interface))
|
||||
{
|
||||
data->ffdbus_message_unref(message);
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* arg2 = "Metadata";
|
||||
if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &arg2))
|
||||
if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &property))
|
||||
{
|
||||
data->ffdbus_message_unref(message);
|
||||
return false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBusPendingCall* pending;
|
||||
bool sendSuccessfull = data->ffdbus_connection_send_with_reply(data->connection, message, &pending, DBUS_TIMEOUT_USE_DEFAULT);
|
||||
data->ffdbus_message_unref(message);
|
||||
if(pending == NULL || !sendSuccessfull)
|
||||
return false;
|
||||
return getReply(message, data);
|
||||
}
|
||||
|
||||
data->ffdbus_connection_flush(data->connection);
|
||||
data->ffdbus_pending_call_block(pending);
|
||||
static void getPropertyString(const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result, DBusData* data)
|
||||
{
|
||||
DBusMessage* reply = getProperty(busName, objectPath, interface, property, data);
|
||||
if(reply == NULL)
|
||||
return;
|
||||
|
||||
DBusMessage* reply = data->ffdbus_pending_call_steal_reply(pending);
|
||||
data->ffdbus_pending_call_unref(pending);
|
||||
DBusMessageIter rootIterator;
|
||||
if(!data->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
data->ffdbus_message_unref(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
getValue(&rootIterator, result, data);
|
||||
|
||||
data->ffdbus_message_unref(reply);
|
||||
}
|
||||
|
||||
static bool getBusProperties(const char* busName, FFMediaResult* result, DBusData* data)
|
||||
{
|
||||
DBusMessage* reply = getProperty(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Metadata", data);
|
||||
if(reply == NULL)
|
||||
return false;
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if(!data->ffdbus_message_iter_init(reply, &rootIterator) || data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT)
|
||||
if(!data->ffdbus_message_iter_init(reply, &rootIterator))
|
||||
{
|
||||
data->ffdbus_message_unref(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT)
|
||||
{
|
||||
data->ffdbus_message_unref(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter variantIterator;
|
||||
data->ffdbus_message_iter_recurse(&rootIterator, &variantIterator);
|
||||
if(data->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY)
|
||||
{
|
||||
data->ffdbus_message_unref(reply);
|
||||
return false;
|
||||
}
|
||||
|
||||
DBusMessageIter arrayIterator;
|
||||
data->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator);
|
||||
@@ -143,18 +187,14 @@ static bool detectSong(const char* player, FFMediaResult* result, DBusData* data
|
||||
|
||||
data->ffdbus_message_iter_next(&dictIterator);
|
||||
|
||||
if(data->ffdbus_message_iter_get_arg_type(&dictIterator) != DBUS_TYPE_VARIANT)
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
|
||||
DBusMessageIter valueIter;
|
||||
data->ffdbus_message_iter_recurse(&dictIterator, &valueIter);
|
||||
|
||||
if(strcmp(key, "xesam:title") == 0)
|
||||
getValue(&valueIter, &result->song, data);
|
||||
getValue(&dictIterator, &result->song, data);
|
||||
else if(strcmp(key, "xesam:album") == 0)
|
||||
getValue(&valueIter, &result->album, data);
|
||||
getValue(&dictIterator, &result->album, data);
|
||||
else if(strcmp(key, "xesam:artist") == 0)
|
||||
getValue(&valueIter, &result->artist, data);
|
||||
getValue(&dictIterator, &result->artist, data);
|
||||
else if(strcmp(key, "xesam:url") == 0)
|
||||
getValue(&dictIterator, &result->url, data);
|
||||
|
||||
if(result->song.length > 0 && result->artist.length > 0 && result->album.length > 0)
|
||||
break;
|
||||
@@ -162,52 +202,52 @@ static bool detectSong(const char* player, FFMediaResult* result, DBusData* data
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
}
|
||||
|
||||
data->ffdbus_message_unref(reply);
|
||||
|
||||
if(result->song.length == 0)
|
||||
{
|
||||
ffStrbufClear(&result->artist);
|
||||
ffStrbufClear(&result->album);
|
||||
ffStrbufClear(&result->url);
|
||||
return false;
|
||||
}
|
||||
|
||||
//We found a song, get the player name
|
||||
|
||||
getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player, data);
|
||||
|
||||
if(result->player.length == 0)
|
||||
getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void getCustomPlayer(FFinstance* instance, FFMediaResult* result, DBusData* data)
|
||||
static void getCustomBus(FFinstance* instance, FFMediaResult* result, DBusData* data)
|
||||
{
|
||||
if(ffStrbufStartsWithS(&instance->config.playerName, FF_DBUS_MPRIS_PREFIX))
|
||||
{
|
||||
detectSong(instance->config.playerName.chars, result, data);
|
||||
ffStrbufAppendS(&result->player, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
|
||||
ffStrbufAppendS(&result->busNameShort, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
|
||||
getBusProperties(instance->config.playerName.chars, result, data);
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufAppend(&result->busNameShort, &instance->config.playerName);
|
||||
|
||||
FFstrbuf busName;
|
||||
ffStrbufInit(&busName);
|
||||
ffStrbufAppendS(&busName, FF_DBUS_MPRIS_PREFIX);
|
||||
ffStrbufAppend(&busName, &instance->config.playerName);
|
||||
detectSong(busName.chars, result, data);
|
||||
getBusProperties(busName.chars, result, data);
|
||||
ffStrbufDestroy(&busName);
|
||||
|
||||
ffStrbufAppend(&result->player, &instance->config.playerName);
|
||||
}
|
||||
|
||||
static void getBestPlayer(FFMediaResult* result, DBusData* data)
|
||||
static void getBestBus(FFMediaResult* result, DBusData* data)
|
||||
{
|
||||
DBusMessage* message = data->ffdbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames");
|
||||
if(message == NULL)
|
||||
return;
|
||||
|
||||
DBusPendingCall* pending;
|
||||
bool sendSuccessfull = data->ffdbus_connection_send_with_reply(data->connection, message, &pending, DBUS_TIMEOUT_USE_DEFAULT);
|
||||
data->ffdbus_message_unref(message);
|
||||
if(pending == NULL || !sendSuccessfull)
|
||||
return;
|
||||
|
||||
data->ffdbus_connection_flush(data->connection);
|
||||
data->ffdbus_pending_call_block(pending);
|
||||
|
||||
DBusMessage* reply = data->ffdbus_pending_call_steal_reply(pending);
|
||||
data->ffdbus_pending_call_unref(pending);
|
||||
DBusMessage* reply = getReply(message, data);
|
||||
if(reply == NULL)
|
||||
return;
|
||||
|
||||
@@ -223,27 +263,29 @@ static void getBestPlayer(FFMediaResult* result, DBusData* data)
|
||||
if(data->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING)
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
|
||||
const char* name;
|
||||
data->ffdbus_message_iter_get_basic(&arrayIterator, &name);
|
||||
const char* busName;
|
||||
data->ffdbus_message_iter_get_basic(&arrayIterator, &busName);
|
||||
|
||||
if(strncmp(name, FF_DBUS_MPRIS_PREFIX, sizeof(FF_DBUS_MPRIS_PREFIX) - 1) != 0)
|
||||
if(strncmp(busName, FF_DBUS_MPRIS_PREFIX, sizeof(FF_DBUS_MPRIS_PREFIX) - 1) != 0)
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
|
||||
if(detectSong(name, result, data))
|
||||
if(getBusProperties(busName, result, data))
|
||||
{
|
||||
ffStrbufAppendS(&result->player, name + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
|
||||
ffStrbufAppendS(&result->busNameShort, busName + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(arrayIterator)
|
||||
}
|
||||
|
||||
data->ffdbus_message_unref(reply);
|
||||
}
|
||||
|
||||
static void getMedia(FFinstance* instance, FFMediaResult* result)
|
||||
{
|
||||
DBusData data;
|
||||
|
||||
FF_LIBRARY_LOAD(dbus, instance->config.libDBus, , "libdbus-1.so", "libdbus-1.so.3");
|
||||
FF_LIBRARY_LOAD(dbus, instance->config.libDBus, , "libdbus-1.so", 4);
|
||||
FF_LIBRARY_LOAD_SYMBOL(dbus, dbus_bus_get,)
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_new_method_call, dbus_message_new_method_call,)
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADRESS(dbus, data.ffdbus_message_iter_init, dbus_message_iter_init,)
|
||||
@@ -269,9 +311,9 @@ static void getMedia(FFinstance* instance, FFMediaResult* result)
|
||||
}
|
||||
|
||||
if(instance->config.playerName.length > 0)
|
||||
getCustomPlayer(instance, result, &data);
|
||||
getCustomBus(instance, result, &data);
|
||||
else
|
||||
getBestPlayer(result, &data);
|
||||
getBestBus(result, &data);
|
||||
|
||||
dlclose(dbus);
|
||||
}
|
||||
@@ -292,23 +334,30 @@ const FFMediaResult* ffDetectMedia(FFinstance* instance)
|
||||
}
|
||||
init = true;
|
||||
|
||||
ffStrbufInit(&result.busNameShort);
|
||||
ffStrbufInit(&result.player);
|
||||
ffStrbufInit(&result.song);
|
||||
ffStrbufInit(&result.artist);
|
||||
ffStrbufInit(&result.album);
|
||||
ffStrbufInit(&result.url);
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
getMedia(instance, &result);
|
||||
#endif
|
||||
|
||||
if(instance->config.playerName.length > 0 && result.player.length == 0)
|
||||
//Set busNameShort if a custom player was given, but loading dbus failed
|
||||
if(instance->config.playerName.length > 0 && result.busNameShort.length == 0)
|
||||
{
|
||||
if(ffStrbufStartsWithS(&instance->config.playerName, FF_DBUS_MPRIS_PREFIX))
|
||||
ffStrbufAppendS(&result.player, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
|
||||
ffStrbufAppendS(&result.busNameShort, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1);
|
||||
else
|
||||
ffStrbufAppend(&result.player, &instance->config.playerName);
|
||||
ffStrbufAppend(&result.busNameShort, &instance->config.playerName);
|
||||
}
|
||||
|
||||
//Set player to busNameShort, if detection failed
|
||||
if(result.player.length == 0)
|
||||
ffStrbufAppend(&result.player, &result.busNameShort);
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return &result;
|
||||
}
|
||||
|
||||
+4
-4
@@ -28,7 +28,7 @@ static void parseFile(const char* fileName, FFOSResult* result)
|
||||
|
||||
#endif
|
||||
|
||||
const FFOSResult* ffDetectOS(FFinstance* instance)
|
||||
const FFOSResult* ffDetectOS(const FFinstance* instance)
|
||||
{
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static FFOSResult result;
|
||||
@@ -64,9 +64,9 @@ const FFOSResult* ffDetectOS(FFinstance* instance)
|
||||
}
|
||||
else
|
||||
{
|
||||
parseFile("/etc/os-release", &result);
|
||||
parseFile("/usr/lib/os-release", &result);
|
||||
parseFile("/etc/lsb-release", &result);
|
||||
parseFile(FASTFETCH_TARGET_DIR_ROOT"/etc/os-release", &result);
|
||||
parseFile(FASTFETCH_TARGET_DIR_USR"/lib/os-release", &result);
|
||||
parseFile(FASTFETCH_TARGET_DIR_ROOT"/etc/lsb-release", &result);
|
||||
}
|
||||
#else
|
||||
ffStrbufSetS(&result.name, "Android");
|
||||
|
||||
@@ -42,20 +42,20 @@ static bool detectFromConfigFile(const FFstrbuf* filename, FFPlasmaResult* resul
|
||||
}
|
||||
|
||||
if(category == PLASMA_CATEGORY_KDE && result->widgetStyle.length == 0)
|
||||
ffGetPropValue(line, "widgetStyle =", &result->widgetStyle);
|
||||
ffParsePropLine(line, "widgetStyle =", &result->widgetStyle);
|
||||
else if(category == PLASMA_CATEGORY_ICONS && result->icons.length == 0)
|
||||
ffGetPropValue(line, "Theme =", &result->icons);
|
||||
ffParsePropLine(line, "Theme =", &result->icons);
|
||||
else if(category == PLASMA_CATEGORY_GENERAL)
|
||||
{
|
||||
if(result->colorScheme.length == 0)
|
||||
ffGetPropValue(line, "ColorScheme =", &result->colorScheme);
|
||||
ffParsePropLine(line, "ColorScheme =", &result->colorScheme);
|
||||
|
||||
if(result->font.length == 0)
|
||||
ffGetPropValue(line, "font =", &result->font);
|
||||
ffParsePropLine(line, "font =", &result->font);
|
||||
|
||||
//Before plasma 5.23, "Font" was the key instead of "font". Since a lot of distros ship older versions, we test for both.
|
||||
if(result->font.length == 0)
|
||||
ffGetPropValue(line, "Font =", &result->font);
|
||||
ffParsePropLine(line, "Font =", &result->font);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ static void getProcessInformation(const char* pid, FFstrbuf* processName, FFstrb
|
||||
{
|
||||
FFstrbuf cmdlineFilePath;
|
||||
ffStrbufInit(&cmdlineFilePath);
|
||||
ffStrbufAppendS(&cmdlineFilePath, "/proc/");
|
||||
ffStrbufAppendS(&cmdlineFilePath, FASTFETCH_TARGET_DIR_ROOT"/proc/");
|
||||
ffStrbufAppendS(&cmdlineFilePath, pid);
|
||||
ffStrbufAppendS(&cmdlineFilePath, "/cmdline");
|
||||
|
||||
@@ -36,7 +36,7 @@ static void getTerminalShell(FFTerminalShellResult* result, const char* pid)
|
||||
{
|
||||
FFstrbuf statFilePath;
|
||||
ffStrbufInit(&statFilePath);
|
||||
ffStrbufAppendS(&statFilePath, "/proc/");
|
||||
ffStrbufAppendS(&statFilePath, FASTFETCH_TARGET_DIR_ROOT"/proc/");
|
||||
ffStrbufAppendS(&statFilePath, pid);
|
||||
ffStrbufAppendS(&statFilePath, "/stat");
|
||||
|
||||
|
||||
+185
-121
@@ -12,8 +12,6 @@ typedef struct FFdata
|
||||
{
|
||||
FFvaluestore valuestore;
|
||||
FFstrbuf structure;
|
||||
FFstrbuf logoName;
|
||||
FFstrbuf logoColors[FASTFETCH_LOGO_MAX_COLORS];
|
||||
bool multithreading;
|
||||
} FFdata;
|
||||
|
||||
@@ -304,16 +302,20 @@ static inline void printCommandHelp(const char* command)
|
||||
}
|
||||
else if(strcasecmp(command, "player-format") == 0)
|
||||
{
|
||||
constructAndPrintCommandHelpFormat("player", "{}", 1,
|
||||
"Player name"
|
||||
constructAndPrintCommandHelpFormat("player", "{}", 3,
|
||||
"Pretty player name",
|
||||
"Player name",
|
||||
"DBus bus name"
|
||||
);
|
||||
}
|
||||
else if(strcasecmp(command, "song-format") == 0)
|
||||
{
|
||||
constructAndPrintCommandHelpFormat("song", "{2} - {3} - {1}", 3,
|
||||
constructAndPrintCommandHelpFormat("song", "{3} - {4} - {1}", 5,
|
||||
"Song name pretty",
|
||||
"Song name",
|
||||
"Artist name",
|
||||
"Album name"
|
||||
"Album name",
|
||||
"Song url"
|
||||
);
|
||||
}
|
||||
else if(strcasecmp(command, "datetime-format") == 0 || strcasecmp(command, "date-format") == 0 || strcasecmp(command, "time-format") == 0)
|
||||
@@ -391,7 +393,7 @@ static inline void listAvailablePresets(FFinstance* instance)
|
||||
ffStrbufAppendS(&folder, "/.local/share/fastfetch/presets/");
|
||||
listAvailablePresetsFromFolder(&folder, 0, NULL);
|
||||
|
||||
ffStrbufSetS(&folder, "/usr/share/fastfetch/presets/");
|
||||
ffStrbufSetS(&folder, FASTFETCH_TARGET_DIR_USR"/share/fastfetch/presets/");
|
||||
listAvailablePresetsFromFolder(&folder, 0, NULL);
|
||||
|
||||
ffStrbufDestroy(&folder);
|
||||
@@ -486,7 +488,7 @@ static void optionParseConfigFile(FFinstance* instance, FFdata* data, const char
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufSetS(&filename, "/usr/share/fastfetch/presets/");
|
||||
ffStrbufSetS(&filename, FASTFETCH_TARGET_DIR_USR"/share/fastfetch/presets/");
|
||||
ffStrbufAppendS(&filename, value);
|
||||
|
||||
file = fopen(filename.chars, "r");
|
||||
@@ -604,33 +606,46 @@ static void optionParseColor(const char* key, const char* value, FFstrbuf* buffe
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t optionParseUInt32(const char* key, const char* value)
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <num>\n", key);
|
||||
exit(480);
|
||||
}
|
||||
|
||||
char* end;
|
||||
uint32_t num = (uint32_t) strtoul(value, &end, 10);
|
||||
if(*end != '\0')
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <num>\n", key);
|
||||
exit(479);
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static void parseOption(FFinstance* instance, FFdata* data, const char* key, const char* value)
|
||||
{
|
||||
///////////////////////
|
||||
//Informative options//
|
||||
///////////////////////
|
||||
|
||||
if(strcasecmp(key, "-h") == 0 || strcasecmp(key, "--help") == 0)
|
||||
{
|
||||
printCommandHelp(value);
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "-v") == 0 || strcasecmp(key, "--version") == 0)
|
||||
{
|
||||
puts("fastfetch "FASTFETCH_PROJECT_VERSION""FASTFETCH_PROJECT_VERSION_TWEAK);
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "--version-raw") == 0)
|
||||
{
|
||||
puts(FASTFETCH_PROJECT_VERSION);
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "--list-logos") == 0)
|
||||
{
|
||||
ffListLogos();
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "--list-logos-autocompletion") == 0)
|
||||
{
|
||||
ffListLogosForAutocompletion();
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "--print-logos") == 0)
|
||||
{
|
||||
ffPrintLogos(instance);
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "--print-config") == 0)
|
||||
{
|
||||
fputs(FASTFETCH_DATATEXT_CONFIG, stdout);
|
||||
@@ -656,32 +671,141 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
|
||||
ffListFeatures();
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "--spacing") == 0)
|
||||
else if(strcasecmp(key, "--list-logos") == 0)
|
||||
{
|
||||
ffListBuiltinLogos();
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "--list-logos-autocompletion") == 0)
|
||||
{
|
||||
ffListBuiltinLogosAutocompletion();
|
||||
exit(0);
|
||||
}
|
||||
else if(strcasecmp(key, "--print-logos") == 0)
|
||||
{
|
||||
ffPrintBuiltinLogos(instance);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
///////////////////
|
||||
//General options//
|
||||
///////////////////
|
||||
|
||||
else if(strcasecmp(key, "-r") == 0 || strcasecmp(key, "--recache") == 0)
|
||||
{
|
||||
//Set cacheSave as well, because the user expects the values to be cached when expliciting using --recache
|
||||
instance->config.recache = optionParseBoolean(value);
|
||||
instance->config.cacheSave = instance->config.recache;
|
||||
}
|
||||
else if(strcasecmp(key, "--nocache") == 0)
|
||||
{
|
||||
instance->config.recache = optionParseBoolean(value);
|
||||
instance->config.cacheSave = false;
|
||||
}
|
||||
else if(strcasecmp(key, "--load-config") == 0)
|
||||
optionParseConfigFile(instance, data, key, value);
|
||||
else if(strcasecmp(key, "--multithreading") == 0)
|
||||
data->multithreading = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--allow-slow-operations") == 0)
|
||||
instance->config.allowSlowOperations = optionParseBoolean(value);
|
||||
|
||||
////////////////
|
||||
//Logo options//
|
||||
////////////////
|
||||
|
||||
else if(strcasecmp(key, "-l") == 0 || strcasecmp(key, "--logo") == 0)
|
||||
optionParseString(key, value, &instance->config.logoSource);
|
||||
else if(strcasecmp(key, "--logo-type") == 0)
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <width>\n", key);
|
||||
exit(404);
|
||||
fprintf(stderr, "Error: usage: %s <type>\n", key);
|
||||
exit(476);
|
||||
}
|
||||
if(sscanf(value, "%hu", &instance->config.logoKeySpacing) != 1)
|
||||
|
||||
if(strcasecmp(value, "auto") == 0)
|
||||
instance->config.logoType = FF_LOGO_TYPE_AUTO;
|
||||
else if(strcasecmp(value, "builtin") == 0)
|
||||
instance->config.logoType = FF_LOGO_TYPE_BUILTIN;
|
||||
else if(strcasecmp(value, "file") == 0)
|
||||
instance->config.logoType = FF_LOGO_TYPE_FILE;
|
||||
else if(strcasecmp(value, "raw") == 0)
|
||||
instance->config.logoType = FF_LOGO_TYPE_RAW;
|
||||
else if(strcasecmp(value, "sixel") == 0)
|
||||
instance->config.logoType = FF_LOGO_TYPE_SIXEL;
|
||||
else if(strcasecmp(value, "kitty") == 0)
|
||||
instance->config.logoType = FF_LOGO_TYPE_KITTY;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: couldn't parse %s to uint16_t\n", value);
|
||||
exit(405);
|
||||
fprintf(stderr, "Error: unknown logo type: %s\n", value);
|
||||
exit(478);
|
||||
}
|
||||
}
|
||||
else if(strcasecmp(key, "-x") == 0 || strcasecmp(key, "--offsetx") == 0)
|
||||
else if(strncasecmp(key, "--logo-color-", 13) == 0 && key[13] != '\0' && key[14] == '\0') // matches "--logo-color-*"
|
||||
{
|
||||
if(value == NULL)
|
||||
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
|
||||
int index = (int)key[13] - 49;
|
||||
|
||||
//Match only --logo-color-[1-9]
|
||||
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <offset>\n", key);
|
||||
exit(408);
|
||||
}
|
||||
if(sscanf(value, "%hi", &instance->config.offsetx) != 1)
|
||||
{
|
||||
fprintf(stderr, "Error: couldn't parse %s to int16_t\n", value);
|
||||
exit(409);
|
||||
fprintf(stderr, "Error: invalid --color-[1-9] index: %c\n", key[13]);
|
||||
exit(472);
|
||||
}
|
||||
|
||||
optionParseColor(key, value, &instance->config.logoColors[index]);
|
||||
}
|
||||
else if(strcasecmp(key, "--logo-width") == 0)
|
||||
instance->config.logoWidth = optionParseUInt32(key, value);
|
||||
else if(strcasecmp(key, "--logo-padding") == 0)
|
||||
{
|
||||
uint32_t padding = optionParseUInt32(key, value);
|
||||
instance->config.logoPaddingLeft = padding;
|
||||
instance->config.logoPaddingRight = padding;
|
||||
}
|
||||
else if(strcasecmp(key, "--logo-padding-left") == 0)
|
||||
instance->config.logoPaddingLeft = optionParseUInt32(key, value);
|
||||
else if(strcasecmp(key, "--logo-padding-right") == 0)
|
||||
instance->config.logoPaddingRight = optionParseUInt32(key, value);
|
||||
else if(strcasecmp(key, "--logo-print-remaining") == 0)
|
||||
instance->config.logoPrintRemaining = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--sixel") == 0)
|
||||
{
|
||||
optionParseString(key, value, &instance->config.logoSource);
|
||||
instance->config.logoType = FF_LOGO_TYPE_SIXEL;
|
||||
}
|
||||
else if(strcasecmp(key, "--kitty") == 0)
|
||||
{
|
||||
optionParseString(key, value, &instance->config.logoSource);
|
||||
instance->config.logoType = FF_LOGO_TYPE_KITTY;
|
||||
}
|
||||
else if(strcasecmp(key, "--file") == 0)
|
||||
{
|
||||
optionCheckString(key, value, &instance->config.logoSource);
|
||||
instance->config.logoType = FF_LOGO_TYPE_FILE;
|
||||
}
|
||||
else if(strcasecmp(key, "--raw") == 0)
|
||||
{
|
||||
optionParseString(key, value, &instance->config.logoSource);
|
||||
instance->config.logoType = FF_LOGO_TYPE_RAW;
|
||||
}
|
||||
|
||||
///////////////////
|
||||
//Display options//
|
||||
///////////////////
|
||||
|
||||
else if(strcasecmp(key, "--show-errors") == 0)
|
||||
instance->config.showErrors = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--disable-linewrap") == 0)
|
||||
instance->config.disableLinewrap = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--hide-cursor") == 0)
|
||||
instance->config.hideCursor = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "-s") == 0 || strcasecmp(key, "--structure") == 0)
|
||||
optionParseString(key, value, &data->structure);
|
||||
else if(strcasecmp(key, "--separator") == 0)
|
||||
optionParseString(key, value, &instance->config.separator);
|
||||
else if(strcasecmp(key, "-c") == 0 || strcasecmp(key, "--color") == 0)
|
||||
optionParseColor(key, value, &instance->config.mainColor);
|
||||
else if(strcasecmp(key, "--set") == 0)
|
||||
{
|
||||
if(value == NULL)
|
||||
@@ -702,43 +826,11 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
|
||||
|
||||
ffValuestoreSet(&data->valuestore, value, separator + 1);
|
||||
}
|
||||
else if(strcasecmp(key, "-r") == 0 || strcasecmp(key, "--recache") == 0)
|
||||
{
|
||||
//Set cacheSave as well, beacuse the user expects the values to be cached when expliciting using --recache
|
||||
instance->config.recache = optionParseBoolean(value);
|
||||
instance->config.cacheSave = instance->config.recache;
|
||||
}
|
||||
else if(strcasecmp(key, "--nocache") == 0)
|
||||
{
|
||||
instance->config.recache = optionParseBoolean(value);
|
||||
instance->config.cacheSave = false;
|
||||
}
|
||||
else if(strcasecmp(key, "--load-config") == 0)
|
||||
optionParseConfigFile(instance, data, key, value);
|
||||
else if(strcasecmp(key, "--show-errors") == 0)
|
||||
instance->config.showErrors = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--color-logo") == 0)
|
||||
instance->config.colorLogo = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--print-remaining-logo") == 0)
|
||||
instance->config.printRemainingLogo = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--multithreading") == 0)
|
||||
data->multithreading = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--allow-slow-operations") == 0)
|
||||
instance->config.allowSlowOperations = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--disable-linewrap") == 0)
|
||||
instance->config.disableLinewrap = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--hide-cursor") == 0)
|
||||
instance->config.hideCursor = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--logo-raw") == 0)
|
||||
instance->config.userLogoIsRaw = optionParseBoolean(value);
|
||||
else if(strcasecmp(key, "--structure") == 0)
|
||||
optionParseString(key, value, &data->structure);
|
||||
else if(strcasecmp(key, "-l") == 0 || strcasecmp(key, "--logo") == 0)
|
||||
optionParseString(key, value, &data->logoName);
|
||||
else if(strcasecmp(key, "-s") == 0 || strcasecmp(key, "--separator") == 0)
|
||||
optionParseString(key, value, &instance->config.separator);
|
||||
else if(strcasecmp(key, "-c") == 0 || strcasecmp(key, "--color") == 0)
|
||||
optionParseColor(key, value, &instance->config.color);
|
||||
|
||||
////////////////////////
|
||||
//Format + Key options//
|
||||
////////////////////////
|
||||
|
||||
else if(strcasecmp(key, "--os-format") == 0)
|
||||
optionParseString(key, value, &instance->config.osFormat);
|
||||
else if(strcasecmp(key, "--os-key") == 0)
|
||||
@@ -863,6 +955,11 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
|
||||
optionParseString(key, value, &instance->config.timeKey);
|
||||
else if(strcasecmp(key, "--time-format") == 0)
|
||||
optionParseString(key, value, &instance->config.timeFormat);
|
||||
|
||||
///////////////////
|
||||
//Library options//
|
||||
///////////////////
|
||||
|
||||
else if(strcasecmp(key, "--lib-PCI") == 0)
|
||||
optionParseString(key, value, &instance->config.libPCI);
|
||||
else if(strcasecmp(key, "--lib-vulkan") == 0)
|
||||
@@ -887,6 +984,15 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
|
||||
optionParseString(key, value, &instance->config.libXFConf);
|
||||
else if(strcasecmp(key, "--lib-rpm") == 0)
|
||||
optionParseString(key, value, &instance->config.librpm);
|
||||
else if(strcasecmp(key, "--lib-imagemagick") == 0)
|
||||
optionParseString(key, value, &instance->config.libImageMagick);
|
||||
else if(strcasecmp(key, "--lib-z") == 0)
|
||||
optionParseString(key, value, &instance->config.libZ);
|
||||
|
||||
//////////////////
|
||||
//Module options//
|
||||
//////////////////
|
||||
|
||||
else if(strcasecmp(key, "--disk-folders") == 0)
|
||||
optionParseString(key, value, &instance->config.diskFolders);
|
||||
else if(strcasecmp(key, "--battery-dir") == 0)
|
||||
@@ -904,33 +1010,12 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con
|
||||
else if(strcasecmp(key, "--player-name") == 0)
|
||||
optionParseString(key, value, &instance->config.playerName);
|
||||
else if(strcasecmp(key, "--public-ip-timeout") == 0)
|
||||
{
|
||||
if(value == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: usage: %s <value>\n", key);
|
||||
exit(465);
|
||||
}
|
||||
instance->config.publicIpTimeout = optionParseUInt32(key, value);
|
||||
|
||||
if(sscanf(value, "%u", &instance->config.publicIpTimeout) != 1)
|
||||
{
|
||||
fprintf(stderr, "Error: couldn't parse %s to uint32_t\n", value);
|
||||
exit(466);
|
||||
}
|
||||
}
|
||||
else if(strncasecmp(key, "--color-", 7) == 0 && key[8] != '\0' && key[9] == '\0') // matches "--color-*"
|
||||
{
|
||||
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
|
||||
int index = (int)key[8] - 49;
|
||||
//////////////////
|
||||
//Unknown option//
|
||||
//////////////////
|
||||
|
||||
//Match only --color-[1-9]
|
||||
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
|
||||
{
|
||||
fprintf(stderr, "Error: invalid --color-[1-9] index: %c\n", key[8]);
|
||||
exit(472);
|
||||
}
|
||||
|
||||
optionParseColor(key, value, &data->logoColors[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: unknown option: %s\n", key);
|
||||
@@ -1080,32 +1165,11 @@ int main(int argc, const char** argv)
|
||||
FFdata data;
|
||||
ffValuestoreInit(&data.valuestore);
|
||||
ffStrbufInitA(&data.structure, 256);
|
||||
ffStrbufInitA(&data.logoName, 0);
|
||||
data.multithreading = true;
|
||||
|
||||
for(uint8_t i = 0; i < FASTFETCH_LOGO_MAX_COLORS; i++)
|
||||
ffStrbufInitA(&data.logoColors[i], 0);
|
||||
|
||||
parseDefaultConfigFile(&instance, &data);
|
||||
parseArguments(&instance, &data, argc, argv);
|
||||
|
||||
//Load custom logo if it exists
|
||||
if(data.logoName.length > 0)
|
||||
ffLoadLogoSet(&instance, data.logoName.chars);
|
||||
else
|
||||
ffLoadLogo(&instance);
|
||||
|
||||
//If we haven't set key color, use primary color of logo
|
||||
if(instance.config.color.length == 0)
|
||||
ffStrbufSet(&instance.config.color, &instance.config.logoColors[0]);
|
||||
|
||||
//Overwrite logo colors with custom colors
|
||||
for(uint8_t i = 0; i < FASTFETCH_LOGO_MAX_COLORS; i++)
|
||||
{
|
||||
if(data.logoColors[i].length > 0)
|
||||
ffStrbufSet(&instance.config.logoColors[i], &data.logoColors[i]);
|
||||
}
|
||||
|
||||
//Start detection threads
|
||||
if(data.multithreading)
|
||||
ffStartDetectionThreads(&instance);
|
||||
|
||||
+83
-72
@@ -31,32 +31,35 @@ static inline void ffUnused(int dummy, ...) { (void) dummy; }
|
||||
|
||||
#define FASTFETCH_LOGO_MAX_COLORS 9 //two digits would make parsing much more complicated (index 1 - 9)
|
||||
|
||||
typedef struct FFlogo
|
||||
typedef enum FFLogoType
|
||||
{
|
||||
const char** names; //Null terminated
|
||||
char* lines;
|
||||
bool isFromUser;
|
||||
const char** builtinColors; // [0] is used as key color, if not user specified
|
||||
} FFlogo;
|
||||
FF_LOGO_TYPE_AUTO, //If something is given, first try builtin, then file. Otherwise detect logo
|
||||
FF_LOGO_TYPE_BUILTIN, //Builtin ascii art.
|
||||
FF_LOGO_TYPE_FILE, //Raw text file, printed as is.
|
||||
FF_LOGO_TYPE_RAW, //Raw text file, printed with color codes replacement.
|
||||
FF_LOGO_TYPE_SIXEL, //Image file, printed as sixel codes.
|
||||
FF_LOGO_TYPE_KITTY //Image file, printed as kitty graphics protocol
|
||||
} FFLogoType;
|
||||
|
||||
typedef struct FFconfig
|
||||
{
|
||||
const FFlogo* logo;
|
||||
FFstrbuf logoSource;
|
||||
FFLogoType logoType;
|
||||
FFstrbuf logoColors[FASTFETCH_LOGO_MAX_COLORS];
|
||||
uint32_t logoWidth;
|
||||
uint32_t logoPaddingLeft;
|
||||
uint32_t logoPaddingRight;
|
||||
bool logoPrintRemaining;
|
||||
|
||||
uint16_t logoKeySpacing;
|
||||
FFstrbuf mainColor; //If this is empty, ffPrintLogo will set it to the main color of the logo
|
||||
FFstrbuf separator;
|
||||
int16_t offsetx;
|
||||
FFstrbuf color;
|
||||
bool colorLogo;
|
||||
|
||||
bool showErrors;
|
||||
bool recache;
|
||||
bool cacheSave;
|
||||
bool printRemainingLogo;
|
||||
bool allowSlowOperations;
|
||||
bool disableLinewrap;
|
||||
bool hideCursor;
|
||||
bool userLogoIsRaw;
|
||||
|
||||
FFstrbuf osFormat;
|
||||
FFstrbuf osKey;
|
||||
@@ -133,6 +136,8 @@ typedef struct FFconfig
|
||||
FFstrbuf libDBus;
|
||||
FFstrbuf libXFConf;
|
||||
FFstrbuf librpm;
|
||||
FFstrbuf libImageMagick;
|
||||
FFstrbuf libZ;
|
||||
|
||||
FFstrbuf diskFolders;
|
||||
|
||||
@@ -154,7 +159,8 @@ typedef struct FFconfig
|
||||
typedef struct FFstate
|
||||
{
|
||||
uint32_t logoWidth;
|
||||
char* logoLinesIndex;
|
||||
uint32_t logoHeight;
|
||||
uint32_t keysHeight;
|
||||
|
||||
struct passwd* passwd;
|
||||
struct utsname utsname;
|
||||
@@ -257,10 +263,12 @@ typedef struct FFTempsResult
|
||||
|
||||
typedef struct FFMediaResult
|
||||
{
|
||||
FFstrbuf player;
|
||||
FFstrbuf busNameShort; //e.g. plasma-browser-integration
|
||||
FFstrbuf player; // e.g. Google Chrome
|
||||
FFstrbuf song;
|
||||
FFstrbuf artist;
|
||||
FFstrbuf album;
|
||||
FFstrbuf url;
|
||||
} FFMediaResult;
|
||||
|
||||
typedef struct FFDateTimeResult
|
||||
@@ -373,9 +381,9 @@ typedef enum FFInitState
|
||||
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
|
||||
__typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADRESS(library, ff ## symbolName, symbolName, returnValue);
|
||||
|
||||
/*************************/
|
||||
/* Common util functions */
|
||||
/*************************/
|
||||
//////////////////////
|
||||
// Common functions //
|
||||
//////////////////////
|
||||
|
||||
//common/init.c
|
||||
void ffInitInstance(FFinstance* instance);
|
||||
@@ -388,37 +396,36 @@ void ffListFeatures();
|
||||
void ffStartDetectionThreads(FFinstance* instance);
|
||||
|
||||
//common/io.c
|
||||
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat);
|
||||
void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numFormatArgs, const char* message, ...);
|
||||
void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments);
|
||||
void ffGetCacheFilePath(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer);
|
||||
void ffReadCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* buffer);
|
||||
void ffWriteCacheFile(FFinstance* instance, const char* moduleName, const char* extension, FFstrbuf* content);
|
||||
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs);
|
||||
void ffPrintAndSaveToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
|
||||
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
|
||||
|
||||
void ffCacheValidate(FFinstance* instance);
|
||||
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache);
|
||||
void ffCacheClose(FFcache* cache);
|
||||
|
||||
void ffAppendFDContent(int fd, FFstrbuf* buffer);
|
||||
bool ffAppendFileContent(const char* fileName, FFstrbuf* buffer); //returns true if open() succeeds. This is used to differentiate between <file not found> and <empty file>
|
||||
bool ffGetFileContent(const char* fileName, FFstrbuf* buffer);
|
||||
bool ffWriteFDContent(int fd, const FFstrbuf* content);
|
||||
void ffWriteFileContent(const char* fileName, const FFstrbuf* buffer);
|
||||
bool ffWriteFileContent(const char* fileName, const FFstrbuf* buffer);
|
||||
|
||||
bool ffFileExists(const char* fileName, mode_t mode);
|
||||
void ffSuppressIO(bool suppress); // Not thread safe!
|
||||
|
||||
// Not thread safe!
|
||||
void ffSuppressIO(bool suppress);
|
||||
void ffGetTerminalResponse(const char* request, char end, const char* format, ...);
|
||||
|
||||
//common/printing.c
|
||||
void ffPrintError(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numFormatArgs, const char* message, ...);
|
||||
void ffPrintFormatString(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments);
|
||||
void ffPrintColor(const FFstrbuf* colorValue);
|
||||
void ffPrintCharTimes(char c, uint32_t times);
|
||||
|
||||
// They return true if the file was found, independently if start was found
|
||||
// Buffers which already contain content are not overwritten
|
||||
// The last occurence of start in the first file will be the one used
|
||||
// The *Values methods always return true, if all properties were already found before, without testing if the file exists
|
||||
//common/caching.c
|
||||
void ffCacheValidate(FFinstance* instance);
|
||||
|
||||
void ffCacheOpenWrite(FFinstance* instance, const char* moduleName, FFcache* cache);
|
||||
void ffCacheClose(FFcache* cache);
|
||||
|
||||
bool ffPrintFromCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* formatString, uint32_t numArgs);
|
||||
void ffPrintAndAppendToCache(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat, FFcache* cache, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
|
||||
void ffPrintAndWriteToCache(FFinstance* instance, const char* moduleName, const FFstrbuf* customKeyFormat, const FFstrbuf* value, const FFstrbuf* formatString, uint32_t numArgs, const FFformatarg* arguments);
|
||||
|
||||
//common/properties.c
|
||||
bool ffParsePropLine(const char* line, const char* start, FFstrbuf* buffer);
|
||||
bool ffParsePropLines(const char* lines, const char* start, FFstrbuf* buffer);
|
||||
bool ffParsePropFileValues(const char* filename, uint32_t numQueries, FFpropquery* queries);
|
||||
bool ffParsePropFile(const char* filename, const char* start, FFstrbuf* buffer);
|
||||
bool ffParsePropFileHomeValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
|
||||
@@ -426,6 +433,21 @@ bool ffParsePropFileHome(const FFinstance* instance, const char* relativeFile, c
|
||||
bool ffParsePropFileConfigValues(const FFinstance* instance, const char* relativeFile, uint32_t numQueries, FFpropquery* queries);
|
||||
bool ffParsePropFileConfig(const FFinstance* instance, const char* relativeFile, const char* start, FFstrbuf* buffer);
|
||||
|
||||
//common/font.c
|
||||
void ffFontInitQt(FFfont* font, const char* data);
|
||||
void ffFontInitPango(FFfont* font, const char* data);
|
||||
void ffFontInitCopy(FFfont* font, const char* name);
|
||||
void ffFontDestroy(FFfont* font);
|
||||
|
||||
//common/format.c
|
||||
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg);
|
||||
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments);
|
||||
|
||||
//common/parsing.c
|
||||
bool ffStrSet(const char* str);
|
||||
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch);
|
||||
void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4);
|
||||
|
||||
//common/processing.c
|
||||
void ffProcessAppendStdOut(FFstrbuf* buffer, char* const argv[]);
|
||||
|
||||
@@ -435,35 +457,6 @@ void* ffLibraryLoad(const FFstrbuf* userProvidedName, ...);
|
||||
//common/networking.c
|
||||
void ffNetworkingGetHttp(const char* host, const char* path, uint32_t timeout, FFstrbuf* buffer);
|
||||
|
||||
//common/logo.c
|
||||
void ffLoadLogoSet(FFinstance* instance, const char* logo);
|
||||
void ffLoadLogo(FFinstance* instance);
|
||||
void ffPrintLogoLine(FFinstance* instance);
|
||||
void ffPrintRemainingLogo(FFinstance* instance);
|
||||
|
||||
void ffPrintLogos(FFinstance* instance);
|
||||
void ffListLogos();
|
||||
void ffListLogosForAutocompletion();
|
||||
|
||||
//common/format.c
|
||||
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg);
|
||||
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, const FFstrbuf* error, uint32_t numArgs, const FFformatarg* arguments);
|
||||
|
||||
//common/parsing.c
|
||||
void ffGetGtkPretty(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, const FFstrbuf* gtk4);
|
||||
|
||||
void ffFontInitQt(FFfont* font, const char* data);
|
||||
void ffFontInitPango(FFfont* font, const char* data);
|
||||
void ffFontInitCopy(FFfont* font, const char* name);
|
||||
void ffFontDestroy(FFfont* font);
|
||||
|
||||
bool ffGetPropValue(const char* line, const char* start, FFstrbuf* buffer);
|
||||
bool ffGetPropValueFromLines(const char* lines, const char* start, FFstrbuf* buffer);
|
||||
|
||||
void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch);
|
||||
|
||||
bool ffStrSet(const char* str);
|
||||
|
||||
//common/settings.c
|
||||
FFvariant ffSettingsGetDConf(FFinstance* instance, const char* key, FFvarianttype type);
|
||||
FFvariant ffSettingsGetGSettings(FFinstance* instance, const char* schemaName, const char* path, const char* key, FFvarianttype type);
|
||||
@@ -474,8 +467,26 @@ FFvariant ffSettingsGetXFConf(FFinstance* instance, const char* channelName, con
|
||||
bool ffSettingsGetAndroidProperty(const char* propName, FFstrbuf* result);
|
||||
#endif
|
||||
|
||||
////////////////////
|
||||
// Logo functions //
|
||||
////////////////////
|
||||
|
||||
void ffPrintLogo(FFinstance* instance);
|
||||
void ffPrintRemainingLogo(FFinstance* instance);
|
||||
|
||||
void ffPrintLogoLine(FFinstance* instance);
|
||||
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat);
|
||||
|
||||
void ffPrintBuiltinLogos(FFinstance* instance);
|
||||
void ffListBuiltinLogos();
|
||||
void ffListBuiltinLogosAutocompletion();
|
||||
|
||||
/////////////////////////
|
||||
// Detection functions //
|
||||
/////////////////////////
|
||||
|
||||
//detection/os.c
|
||||
const FFOSResult* ffDetectOS(FFinstance* instance);
|
||||
const FFOSResult* ffDetectOS(const FFinstance* instance);
|
||||
|
||||
//detection/plasma.c
|
||||
const FFPlasmaResult* ffDetectPlasma(FFinstance* instance);
|
||||
@@ -500,9 +511,9 @@ const FFMediaResult* ffDetectMedia(FFinstance* instance);
|
||||
//detection/dateTime.c
|
||||
const FFDateTimeResult* ffDetectDateTime(const FFinstance* instance);
|
||||
|
||||
/********************/
|
||||
/* Module functions */
|
||||
/********************/
|
||||
//////////////////////
|
||||
// Module functions //
|
||||
//////////////////////
|
||||
|
||||
//Common
|
||||
const FFTitleResult* ffDetectTitle(FFinstance* instance);
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
#define FASTFETCH_PROJECT_NAME "@PROJECT_NAME@"
|
||||
#define FASTFETCH_PROJECT_VERSION "@PROJECT_VERSION@"
|
||||
#define FASTFETCH_PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
|
||||
#define FASTFETCH_PROJECT_VERSION_TWEAK "@PROJECT_VERSION_TWEAK@"
|
||||
|
||||
#define FASTFETCH_TARGET_DIR_ROOT "@TARGET_DIR_ROOT@"
|
||||
#define FASTFETCH_TARGET_DIR_USR "@TARGET_DIR_USR@"
|
||||
#define FASTFETCH_TARGET_DIR_HOME "@TARGET_DIR_HOME@"
|
||||
|
||||
#define FASTFETCH_DATATEXT_STRUCTURE "@DATATEXT_STRUCTURE@"
|
||||
#define FASTFETCH_DATATEXT_CONFIG "@DATATEXT_CONFIG@" //Requires FASTFETCH_PROJECT_VERSION and FASTFETCH_DATATEXT_STRUCTURE to be set
|
||||
|
||||
@@ -10,9 +10,6 @@ int main(int argc, char** argv)
|
||||
|
||||
//Modify instance.config here
|
||||
|
||||
ffLoadLogo(&instance); //ffLoadLogoSet(&instance, "my custom logo");
|
||||
ffStrbufSet(&instance.config.color, &instance.config.logoColors[0]); //Use the primary color of the logo as key color
|
||||
|
||||
//Multithreading --> better performance
|
||||
ffStartDetectionThreads(&instance);
|
||||
|
||||
|
||||
+1484
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,29 @@
|
||||
#ifdef FF_HAVE_IMAGEMAGICK6
|
||||
|
||||
#include "image.h"
|
||||
#include <magick/MagickCore.h>
|
||||
|
||||
static FF_LIBRARY_SYMBOL(ResizeImage);
|
||||
|
||||
static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo)
|
||||
{
|
||||
return ffResizeImage(image, width, height, UndefinedFilter, 1.0, exceptionInfo);
|
||||
}
|
||||
|
||||
FFLogoImageResult ffLogoPrintImageIM6(FFinstance* instance, FFLogoRequestData* requestData)
|
||||
{
|
||||
FF_LIBRARY_LOAD(imageMagick, instance->config.libImageMagick, FF_LOGO_IMAGE_RESULT_INIT_ERROR, "libMagickCore-6.Q16HDRI.so", 8, "libMagickCore-6.Q16.so", 8)
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR);
|
||||
|
||||
FFIMData imData;
|
||||
imData.resizeFunc = logoResize;
|
||||
imData.library = imageMagick;
|
||||
|
||||
FFLogoImageResult result = ffLogoPrintImageImpl(instance, requestData, &imData);
|
||||
|
||||
dlclose(imageMagick);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifdef FF_HAVE_IMAGEMAGICK7
|
||||
|
||||
#include "image.h"
|
||||
#include <MagickCore/MagickCore.h>
|
||||
|
||||
static FF_LIBRARY_SYMBOL(ResizeImage);
|
||||
|
||||
static void* logoResize(const void* image, size_t width, size_t height, void* exceptionInfo)
|
||||
{
|
||||
return ffResizeImage(image, width, height, UndefinedFilter, exceptionInfo);
|
||||
}
|
||||
|
||||
FFLogoImageResult ffLogoPrintImageIM7(FFinstance* instance, FFLogoRequestData* requestData)
|
||||
{
|
||||
FF_LIBRARY_LOAD(imageMagick, instance->config.libImageMagick, FF_LOGO_IMAGE_RESULT_INIT_ERROR, "libMagickCore-7.Q16HDRI.so", 11, "libMagickCore-7.Q16.so", 11)
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR);
|
||||
|
||||
FFIMData imData;
|
||||
imData.resizeFunc = logoResize;
|
||||
imData.library = imageMagick;
|
||||
|
||||
FFLogoImageResult result = ffLogoPrintImageImpl(instance, requestData, &imData);
|
||||
|
||||
dlclose(imageMagick);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,404 @@
|
||||
#include "image.h"
|
||||
|
||||
#if defined(FF_HAVE_IMAGEMAGICK7) || defined(FF_HAVE_IMAGEMAGICK6)
|
||||
|
||||
#define FF_KITTY_MAX_CHUNK_SIZE 4096
|
||||
|
||||
#define FF_CACHE_FILE_HEIGHT "height"
|
||||
#define FF_CACHE_FILE_SIXEL "sixel"
|
||||
#define FF_CACHE_FILE_KITTY_COMPRESSED "kittyc"
|
||||
#define FF_CACHE_FILE_KITTY_UNCOMPRESSED "kittyu"
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
#include <zlib.h>
|
||||
|
||||
static bool compressBlob(const FFinstance* instance, void** blob, size_t* length)
|
||||
{
|
||||
FF_LIBRARY_LOAD(zlib, instance->config.libZ, false, "libz.so", 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL(zlib, compressBound, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(zlib, compress2, false)
|
||||
|
||||
uLong compressedLength = ffcompressBound(*length);
|
||||
void* compressed = malloc(compressedLength);
|
||||
if(compressed == NULL)
|
||||
{
|
||||
dlclose(zlib);
|
||||
return false;
|
||||
}
|
||||
|
||||
int compressResult = ffcompress2(compressed, &compressedLength, *blob, *length, Z_BEST_COMPRESSION);
|
||||
dlclose(zlib);
|
||||
if(compressResult != Z_OK)
|
||||
{
|
||||
free(compressed);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(*blob);
|
||||
|
||||
*length = (size_t) compressedLength;
|
||||
*blob = compressed;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // FF_HAVE_ZLIB
|
||||
|
||||
//We use only the defines from here, that are exactly the same in both versions
|
||||
#ifdef FF_HAVE_IMAGEMAGICK7
|
||||
#include <MagickCore/MagickCore.h>
|
||||
#else
|
||||
#include <magick/MagickCore.h>
|
||||
#endif
|
||||
|
||||
typedef struct ImageData
|
||||
{
|
||||
FF_LIBRARY_SYMBOL(CopyMagickString)
|
||||
FF_LIBRARY_SYMBOL(ImageToBlob)
|
||||
FF_LIBRARY_SYMBOL(Base64Encode)
|
||||
|
||||
ImageInfo* imageInfo;
|
||||
Image* image;
|
||||
ExceptionInfo* exceptionInfo;
|
||||
} ImageData;
|
||||
|
||||
static inline bool checkAllocationResult(void* data, size_t length)
|
||||
{
|
||||
if(data == NULL)
|
||||
return false;
|
||||
|
||||
if(length == 0)
|
||||
{
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void finishPrinting(FFinstance* instance, const FFLogoRequestData* requestData)
|
||||
{
|
||||
instance->state.logoWidth = (uint32_t) (requestData->imagePixelWidth / requestData->characterPixelWidth) + instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
|
||||
instance->state.logoHeight = (uint32_t) (requestData->imagePixelHeight / requestData->characterPixelHeight);
|
||||
|
||||
//Seems to be required on all consoles that support sixel. TBH i don't know why.
|
||||
if(requestData->type == FF_LOGO_TYPE_SIXEL)
|
||||
instance->state.logoHeight += 1;
|
||||
|
||||
fputs("\033[9999999D", stdout);
|
||||
printf("\033[%uA", instance->state.logoHeight);
|
||||
}
|
||||
|
||||
static void writeResult(FFinstance* instance, FFLogoRequestData* requestData, const FFstrbuf* result, const char* cacheFileName)
|
||||
{
|
||||
//Write result to stdout
|
||||
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
|
||||
fflush(stdout);
|
||||
ffWriteFDContent(STDOUT_FILENO, result);
|
||||
|
||||
//Write result to cache file
|
||||
uint32_t cacheDirLength = requestData->cacheDir.length;
|
||||
ffStrbufAppendS(&requestData->cacheDir, cacheFileName);
|
||||
ffWriteFileContent(requestData->cacheDir.chars, result);
|
||||
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
|
||||
|
||||
//Write height cache file
|
||||
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_HEIGHT);
|
||||
FFstrbuf content;
|
||||
content.chars = (char*) &requestData->imagePixelHeight;
|
||||
content.length = sizeof(requestData->imagePixelHeight);
|
||||
ffWriteFileContent(requestData->cacheDir.chars, &content);
|
||||
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
|
||||
|
||||
//Write escape codes to stdout
|
||||
finishPrinting(instance, requestData);
|
||||
}
|
||||
|
||||
static bool printImageSixel(FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
|
||||
{
|
||||
imageData->ffCopyMagickString(imageData->imageInfo->magick, "SIXEL", 6);
|
||||
|
||||
size_t length;
|
||||
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
|
||||
if(!checkAllocationResult(blob, length))
|
||||
return false;
|
||||
|
||||
FFstrbuf result;
|
||||
result.chars = (char*) blob;
|
||||
result.length = (uint32_t) length;
|
||||
|
||||
writeResult(instance, requestData, &result, FF_CACHE_FILE_SIXEL);
|
||||
|
||||
free(blob);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void appendKittyChunk(FFstrbuf* result, const char** blob, size_t* length, bool printEscapeCode)
|
||||
{
|
||||
uint32_t chunkSize = *length > FF_KITTY_MAX_CHUNK_SIZE ? FF_KITTY_MAX_CHUNK_SIZE : (uint32_t) *length;
|
||||
|
||||
if(printEscapeCode)
|
||||
ffStrbufAppendS(result, "\033_G");
|
||||
else
|
||||
ffStrbufAppendC(result, ',');
|
||||
|
||||
ffStrbufAppendS(result, chunkSize != *length ? "m=1" : "m=0");
|
||||
ffStrbufAppendC(result, ';');
|
||||
ffStrbufAppendNS(result, chunkSize, *blob);
|
||||
ffStrbufAppendS(result, "\033\\");
|
||||
*length -= chunkSize;
|
||||
*blob += chunkSize;
|
||||
}
|
||||
|
||||
static bool printImageKitty(FFinstance* instance, FFLogoRequestData* requestData, const ImageData* imageData)
|
||||
{
|
||||
imageData->ffCopyMagickString(imageData->imageInfo->magick, "RGBA", 5);
|
||||
|
||||
size_t length;
|
||||
void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo);
|
||||
if(!checkAllocationResult(blob, length))
|
||||
return false;
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
bool isCompressed = compressBlob(instance, &blob, &length);
|
||||
#else
|
||||
bool isCompressed = false;
|
||||
#endif
|
||||
|
||||
char* chars = imageData->ffBase64Encode(blob, length, &length);
|
||||
free(blob);
|
||||
if(!checkAllocationResult(chars, length))
|
||||
return false;
|
||||
|
||||
FFstrbuf result;
|
||||
ffStrbufInitA(&result, (uint32_t) (length + 1024));
|
||||
|
||||
const char* currentPos = chars;
|
||||
size_t remainingLength = length;
|
||||
|
||||
ffStrbufAppendF(&result, "\033_Ga=T,f=32,s=%u,v=%u", requestData->imagePixelWidth, requestData->imagePixelHeight);
|
||||
if(isCompressed)
|
||||
ffStrbufAppendS(&result, ",o=z");
|
||||
appendKittyChunk(&result, ¤tPos, &remainingLength, false);
|
||||
while(remainingLength > 0)
|
||||
appendKittyChunk(&result, ¤tPos, &remainingLength, true);
|
||||
|
||||
writeResult(instance, requestData, &result, isCompressed ? FF_CACHE_FILE_KITTY_COMPRESSED : FF_CACHE_FILE_KITTY_UNCOMPRESSED);
|
||||
|
||||
ffStrbufDestroy(&result);
|
||||
free(chars);
|
||||
return true;
|
||||
}
|
||||
|
||||
FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData* requestData, const FFIMData* imData)
|
||||
{
|
||||
FF_LIBRARY_LOAD_SYMBOL(imData->library, AcquireExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyExceptionInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
FF_LIBRARY_LOAD_SYMBOL(imData->library, AcquireImageInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyImageInfo, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
FF_LIBRARY_LOAD_SYMBOL(imData->library, ReadImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
FF_LIBRARY_LOAD_SYMBOL(imData->library, DestroyImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
|
||||
ImageData imageData;
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffCopyMagickString, CopyMagickString, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffImageToBlob, ImageToBlob, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
FF_LIBRARY_LOAD_SYMBOL_ADRESS(imData->library, imageData.ffBase64Encode, Base64Encode, FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
|
||||
imageData.exceptionInfo = ffAcquireExceptionInfo();
|
||||
if(imageData.exceptionInfo == NULL)
|
||||
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
||||
|
||||
ImageInfo* imageInfoIn = ffAcquireImageInfo();
|
||||
if(imageInfoIn == NULL)
|
||||
{
|
||||
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
||||
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
||||
}
|
||||
|
||||
//+1, because we need to copy the null byte too
|
||||
imageData.ffCopyMagickString(imageInfoIn->filename, instance->config.logoSource.chars, instance->config.logoSource.length + 1);
|
||||
|
||||
Image* originalImage = ffReadImage(imageInfoIn, imageData.exceptionInfo);
|
||||
ffDestroyImageInfo(imageInfoIn);
|
||||
if(originalImage == NULL)
|
||||
{
|
||||
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
||||
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
||||
}
|
||||
|
||||
//imagePixelWidth is set in ffLogoPrintImageIfExists
|
||||
requestData->imagePixelHeight = (uint32_t) ((requestData->imagePixelWidth / (double) originalImage->columns) * (double) originalImage->rows);
|
||||
if(requestData->imagePixelHeight < 1)
|
||||
{
|
||||
ffDestroyImage(originalImage);
|
||||
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
||||
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
||||
}
|
||||
|
||||
imageData.image = (Image*) imData->resizeFunc(originalImage, requestData->imagePixelWidth, requestData->imagePixelHeight, imageData.exceptionInfo);
|
||||
ffDestroyImage(originalImage);
|
||||
if(imageData.image == NULL)
|
||||
{
|
||||
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
||||
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
||||
}
|
||||
|
||||
imageData.imageInfo = ffAcquireImageInfo();
|
||||
if(imageData.imageInfo == NULL)
|
||||
{
|
||||
ffDestroyImage(imageData.image);
|
||||
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
||||
return FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
||||
}
|
||||
|
||||
bool printSuccessful;
|
||||
if(requestData->type == FF_LOGO_TYPE_KITTY)
|
||||
printSuccessful = printImageKitty(instance, requestData, &imageData);
|
||||
else
|
||||
printSuccessful = printImageSixel(instance, requestData, &imageData);
|
||||
|
||||
ffDestroyImageInfo(imageData.imageInfo);
|
||||
ffDestroyImage(imageData.image);
|
||||
ffDestroyExceptionInfo(imageData.exceptionInfo);
|
||||
|
||||
return printSuccessful ? FF_LOGO_IMAGE_RESULT_SUCCESS : FF_LOGO_IMAGE_RESULT_RUN_ERROR;
|
||||
}
|
||||
|
||||
static int getCacheFD(FFLogoRequestData* requestData, const char* fileName)
|
||||
{
|
||||
uint32_t cacheDirLength = requestData->cacheDir.length;
|
||||
ffStrbufAppendS(&requestData->cacheDir, fileName);
|
||||
int fd = open(requestData->cacheDir.chars, O_RDONLY);
|
||||
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
|
||||
return fd;
|
||||
}
|
||||
|
||||
static bool printCached(FFinstance* instance, FFLogoRequestData* requestData)
|
||||
{
|
||||
uint32_t cacheDirLength = requestData->cacheDir.length;
|
||||
ffStrbufAppendS(&requestData->cacheDir, FF_CACHE_FILE_HEIGHT);
|
||||
|
||||
FFstrbuf content;
|
||||
ffStrbufInitA(&content, sizeof(requestData->imagePixelHeight) + 1); // +1 because strbuf is null terminated
|
||||
memset(content.chars, 0, sizeof(requestData->imagePixelHeight));
|
||||
|
||||
ffAppendFileContent(requestData->cacheDir.chars, &content);
|
||||
memcpy(&requestData->imagePixelHeight, content.chars, sizeof(requestData->imagePixelHeight));
|
||||
|
||||
ffStrbufDestroy(&content);
|
||||
ffStrbufSubstrBefore(&requestData->cacheDir, cacheDirLength);
|
||||
|
||||
if(requestData->imagePixelHeight < 1)
|
||||
return false;
|
||||
|
||||
int fd;
|
||||
if(requestData->type == FF_LOGO_TYPE_KITTY)
|
||||
{
|
||||
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_COMPRESSED);
|
||||
if(fd == -1)
|
||||
fd = getCacheFD(requestData, FF_CACHE_FILE_KITTY_UNCOMPRESSED);
|
||||
}
|
||||
else
|
||||
fd = getCacheFD(requestData, FF_CACHE_FILE_SIXEL);
|
||||
|
||||
if(fd == -1)
|
||||
return false;
|
||||
|
||||
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
|
||||
fflush(stdout);
|
||||
|
||||
char buffer[32768];
|
||||
ssize_t readBytes;
|
||||
while((readBytes = read(fd, buffer, sizeof(buffer))) > 0)
|
||||
(void) write(STDOUT_FILENO, buffer, (size_t) readBytes);
|
||||
|
||||
close(fd);
|
||||
|
||||
finishPrinting(instance, requestData);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool getTermInfo(struct winsize* winsize)
|
||||
{
|
||||
//Initialize every member to 0, because it isn't guaranteed that every terminal sets them all
|
||||
memset(winsize, 0, sizeof(struct winsize));
|
||||
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, winsize);
|
||||
|
||||
if(winsize->ws_row == 0 || winsize->ws_col == 0)
|
||||
ffGetTerminalResponse("\033[18t", 't', "\033[8;%hu;%hut", &winsize->ws_row, &winsize->ws_col);
|
||||
|
||||
if(winsize->ws_ypixel == 0 || winsize->ws_xpixel == 0)
|
||||
ffGetTerminalResponse("\033[14t", 't', "\033[4;%hu;%hut", &winsize->ws_ypixel, &winsize->ws_xpixel);
|
||||
|
||||
return
|
||||
winsize->ws_row > 0 &&
|
||||
winsize->ws_col > 0 &&
|
||||
winsize->ws_ypixel > 0 &&
|
||||
winsize->ws_xpixel > 0;
|
||||
}
|
||||
|
||||
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
|
||||
{
|
||||
FFLogoRequestData requestData;
|
||||
|
||||
if(!getTermInfo(&requestData.winsize))
|
||||
return false;
|
||||
|
||||
requestData.type = type;
|
||||
requestData.characterPixelWidth = requestData.winsize.ws_xpixel / (double) requestData.winsize.ws_col;
|
||||
requestData.characterPixelHeight = requestData.winsize.ws_ypixel / (double) requestData.winsize.ws_row;
|
||||
requestData.imagePixelWidth = (uint32_t) (instance->config.logoWidth * requestData.characterPixelWidth);
|
||||
if(requestData.imagePixelWidth < 1)
|
||||
return false;
|
||||
|
||||
ffStrbufInitA(&requestData.cacheDir, PATH_MAX * 2);
|
||||
ffStrbufAppend(&requestData.cacheDir, &instance->state.cacheDir);
|
||||
ffStrbufAppendS(&requestData.cacheDir, "images");
|
||||
|
||||
ffStrbufEnsureFree(&requestData.cacheDir, PATH_MAX);
|
||||
if(realpath(instance->config.logoSource.chars, requestData.cacheDir.chars + requestData.cacheDir.length) == NULL)
|
||||
{
|
||||
//We can safely return here, because if realpath failed, we surely won't be able to read the file
|
||||
ffStrbufDestroy(&requestData.cacheDir);
|
||||
return false;
|
||||
}
|
||||
ffStrbufRecalculateLength(&requestData.cacheDir);
|
||||
if(!ffStrbufEndsWithC(&requestData.cacheDir, '/'))
|
||||
ffStrbufAppendC(&requestData.cacheDir, '/');
|
||||
|
||||
ffStrbufAppendF(&requestData.cacheDir, "%u", requestData.imagePixelWidth);
|
||||
ffStrbufAppendC(&requestData.cacheDir, '/');
|
||||
|
||||
if(!instance->config.recache && printCached(instance, &requestData))
|
||||
{
|
||||
ffStrbufDestroy(&requestData.cacheDir);
|
||||
return true;
|
||||
}
|
||||
|
||||
FFLogoImageResult result = FF_LOGO_IMAGE_RESULT_INIT_ERROR;
|
||||
|
||||
#ifdef FF_HAVE_IMAGEMAGICK7
|
||||
result = ffLogoPrintImageIM7(instance, &requestData);
|
||||
#endif
|
||||
|
||||
#ifdef FF_HAVE_IMAGEMAGICK6
|
||||
if(result == FF_LOGO_IMAGE_RESULT_INIT_ERROR)
|
||||
result = ffLogoPrintImageIM6(instance, &requestData);
|
||||
#endif
|
||||
|
||||
ffStrbufDestroy(&requestData.cacheDir);
|
||||
return result == FF_LOGO_IMAGE_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
#else //FF_HAVE_IMAGEMAGICK{6, 7}
|
||||
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type)
|
||||
{
|
||||
FF_UNUSED(instance, type);
|
||||
return false;
|
||||
}
|
||||
#endif //FF_HAVE_IMAGEMAGICK{6, 7}
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef FF_INCLUDED_LOGO_SIXEL_sixel
|
||||
#define FF_INCLUDED_LOGO_SIXEL_sixel
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
#if defined(FF_HAVE_IMAGEMAGICK7) || defined(FF_HAVE_IMAGEMAGICK6)
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#define MAGICKCORE_HDRI_ENABLE 1
|
||||
#define MAGICKCORE_QUANTUM_DEPTH 16
|
||||
|
||||
typedef enum FFLogoImageResult
|
||||
{
|
||||
FF_LOGO_IMAGE_RESULT_SUCCESS, //Logo printed
|
||||
FF_LOGO_IMAGE_RESULT_INIT_ERROR, //Failed to load library, try again with next IM version
|
||||
FF_LOGO_IMAGE_RESULT_RUN_ERROR //Failed to load / convert image, cancle whole sixel code
|
||||
} FFLogoImageResult;
|
||||
|
||||
typedef struct FFLogoRequestData
|
||||
{
|
||||
FFLogoType type;
|
||||
FFstrbuf cacheDir;
|
||||
|
||||
struct winsize winsize;
|
||||
double characterPixelWidth;
|
||||
double characterPixelHeight;
|
||||
uint32_t imagePixelWidth;
|
||||
uint32_t imagePixelHeight;
|
||||
} FFLogoRequestData;
|
||||
|
||||
typedef struct FFIMData
|
||||
{
|
||||
void* library;
|
||||
void*(*resizeFunc)(const void* image, size_t width, size_t height, void* exceptionInfo);
|
||||
} FFIMData;
|
||||
|
||||
FFLogoImageResult ffLogoPrintImageImpl(FFinstance* instance, FFLogoRequestData* requestData, const FFIMData* imData);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FF_HAVE_IMAGEMAGICK7
|
||||
FFLogoImageResult ffLogoPrintImageIM7(FFinstance* instance, FFLogoRequestData* requestData);
|
||||
#endif
|
||||
|
||||
#ifdef FF_HAVE_IMAGEMAGICK6
|
||||
#include <math.h>
|
||||
FFLogoImageResult ffLogoPrintImageIM6(FFinstance* instance, FFLogoRequestData* requestData);
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
+256
@@ -0,0 +1,256 @@
|
||||
#include "logo.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement)
|
||||
{
|
||||
uint32_t currentlineLength = 0;
|
||||
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
|
||||
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
|
||||
|
||||
//Use logoColor[0] as the default color
|
||||
if(doColorReplacement)
|
||||
ffPrintColor(&instance->config.logoColors[0]);
|
||||
|
||||
while(*data != '\0')
|
||||
{
|
||||
//We are at the end of a line. Print paddings and update max line length
|
||||
if(*data == '\n' || (*data == '\r' && *(data + 1) == '\n'))
|
||||
{
|
||||
ffPrintCharTimes(' ', instance->config.logoPaddingRight);
|
||||
|
||||
//We have \r\n, skip the \r
|
||||
if(*data == '\r')
|
||||
++data;
|
||||
|
||||
putchar('\n');
|
||||
++data;
|
||||
|
||||
ffPrintCharTimes(' ', instance->config.logoPaddingLeft);
|
||||
|
||||
if(currentlineLength > instance->state.logoWidth)
|
||||
instance->state.logoWidth = currentlineLength;
|
||||
|
||||
currentlineLength = 0;
|
||||
++instance->state.logoHeight;
|
||||
continue;
|
||||
}
|
||||
|
||||
//Always print tabs as 4 spaces, to have consistent spacing
|
||||
if(*data == '\t')
|
||||
{
|
||||
ffPrintCharTimes(' ', 4);
|
||||
++data;
|
||||
continue;
|
||||
}
|
||||
|
||||
//We have an escape sequence direclty as bytes. We print it, but don't increase the line length
|
||||
if(*data == '\033' && *(data + 1) == '[')
|
||||
{
|
||||
const char* start = data;
|
||||
|
||||
fputs("\033[", stdout);
|
||||
data += 2;
|
||||
|
||||
while(isdigit(*data) || *data == ';')
|
||||
putchar(*data++); // number
|
||||
|
||||
//We have a valid control sequence, print it and continue with next char
|
||||
if(isascii(*data))
|
||||
{
|
||||
putchar(*data++); // single letter, end of control sequence
|
||||
continue;
|
||||
}
|
||||
|
||||
//Invalid control sequence, try to get most accurate length
|
||||
currentlineLength += (uint32_t) (data - start - 1); //-1 for \033 which for sure doesn't take any space
|
||||
|
||||
//Don't continue here, print the char after the letters with the unicode printing
|
||||
}
|
||||
|
||||
//We have a fastfetch color placeholder. Replace it with the esacape sequence, don't increase the line length
|
||||
if(doColorReplacement && *data == '$')
|
||||
{
|
||||
++data;
|
||||
|
||||
//If we have $$, or $\0, print it as single $
|
||||
if(*data == '$' || *data == '\0')
|
||||
{
|
||||
putchar('$');
|
||||
++currentlineLength;
|
||||
++data;
|
||||
continue;
|
||||
}
|
||||
|
||||
//Map the number to an array index, so that '1' -> 0, '2' -> 1, etc.
|
||||
int index = ((int) *data) - 49;
|
||||
|
||||
//If the index is valid, print the color. Otherwise continue as normal
|
||||
if(index < 0 || index >= FASTFETCH_LOGO_MAX_COLORS)
|
||||
{
|
||||
putchar('$');
|
||||
++currentlineLength;
|
||||
//Don't continue here, we want to print the current char as unicode
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintColor(&instance->config.logoColors[index]);
|
||||
++data;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//Do the printing, respecting unicode
|
||||
|
||||
++currentlineLength;
|
||||
|
||||
int codepoint = (unsigned char) *data;
|
||||
uint8_t bytes;
|
||||
|
||||
if(codepoint <= 127)
|
||||
bytes = 1;
|
||||
else if((codepoint & 0xE0) == 0xC0)
|
||||
bytes = 2;
|
||||
else if((codepoint & 0xF0) == 0xE0)
|
||||
bytes = 3;
|
||||
else if((codepoint & 0xF8) == 0xF0)
|
||||
bytes = 4;
|
||||
else
|
||||
bytes = 1; //Invalid utf8, print it as is, byte by byte
|
||||
|
||||
for(uint8_t i = 0; i < bytes; ++i)
|
||||
{
|
||||
if(*data == '\0')
|
||||
break;
|
||||
|
||||
putchar(*data++);
|
||||
}
|
||||
}
|
||||
|
||||
ffPrintCharTimes(' ', instance->config.logoPaddingRight);
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
|
||||
//Happens if the last line is the longest
|
||||
if(currentlineLength > instance->state.logoWidth)
|
||||
instance->state.logoWidth = currentlineLength;
|
||||
|
||||
instance->state.logoWidth += instance->config.logoPaddingLeft + instance->config.logoPaddingRight;
|
||||
|
||||
//Go to the leftmost position
|
||||
fputs("\033[9999999D", stdout);
|
||||
|
||||
//If the logo height is > 1, go up the height
|
||||
if(instance->state.logoHeight > 0)
|
||||
printf("\033[%uA", instance->state.logoHeight);
|
||||
}
|
||||
|
||||
static void logoPrintFile(FFinstance* instance, bool doColorReplacement)
|
||||
{
|
||||
FFstrbuf content;
|
||||
ffStrbufInitA(&content, 2047);
|
||||
|
||||
if(ffAppendFileContent(instance->config.logoSource.chars, &content))
|
||||
ffLogoPrint(instance, content.chars, doColorReplacement);
|
||||
else
|
||||
ffLogoPrintUnknown(instance);
|
||||
}
|
||||
|
||||
static void logoPrintDetected(FFinstance* instance)
|
||||
{
|
||||
if(instance->config.logoSource.length > 0)
|
||||
{
|
||||
if(
|
||||
!ffLogoPrintBuiltinIfExists(instance) &&
|
||||
!ffLogoPrintImageIfExists(instance, FF_LOGO_TYPE_KITTY)
|
||||
) logoPrintFile(instance, true);
|
||||
return;
|
||||
}
|
||||
|
||||
ffLogoPrintBuiltinDetected(instance);
|
||||
}
|
||||
|
||||
void ffPrintLogo(FFinstance* instance)
|
||||
{
|
||||
if(instance->config.mainColor.length == 0)
|
||||
ffLogoSetMainColor(instance);
|
||||
|
||||
if(( //Logo type needs set logo name, but nothing was given. Print question mark
|
||||
instance->config.logoType == FF_LOGO_TYPE_BUILTIN ||
|
||||
instance->config.logoType == FF_LOGO_TYPE_FILE ||
|
||||
instance->config.logoType == FF_LOGO_TYPE_RAW ||
|
||||
instance->config.logoType == FF_LOGO_TYPE_SIXEL
|
||||
) && instance->config.logoSource.length == 0)
|
||||
ffLogoPrintUnknown(instance);
|
||||
else if(instance->config.logoType == FF_LOGO_TYPE_BUILTIN)
|
||||
{
|
||||
if(!ffLogoPrintBuiltinIfExists(instance))
|
||||
ffLogoPrintUnknown(instance);
|
||||
}
|
||||
else if(instance->config.logoType == FF_LOGO_TYPE_FILE)
|
||||
logoPrintFile(instance, true);
|
||||
else if(instance->config.logoType == FF_LOGO_TYPE_RAW)
|
||||
logoPrintFile(instance, false);
|
||||
else if(instance->config.logoType == FF_LOGO_TYPE_SIXEL || instance->config.logoType == FF_LOGO_TYPE_KITTY)
|
||||
{
|
||||
if(!ffLogoPrintImageIfExists(instance, instance->config.logoType))
|
||||
ffLogoPrintBuiltinDetected(instance);
|
||||
}
|
||||
else
|
||||
logoPrintDetected(instance);
|
||||
}
|
||||
|
||||
static inline void printLogoWidth(const FFinstance* instance)
|
||||
{
|
||||
if(instance->state.logoWidth > 0)
|
||||
printf("\033[%uC", instance->state.logoWidth);
|
||||
}
|
||||
|
||||
void ffPrintRemainingLogo(FFinstance* instance)
|
||||
{
|
||||
if(!instance->config.logoPrintRemaining)
|
||||
return;
|
||||
|
||||
for(uint32_t i = instance->state.keysHeight; i <= instance->state.logoHeight; i++)
|
||||
{
|
||||
printLogoWidth(instance);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
void ffPrintLogoLine(FFinstance* instance)
|
||||
{
|
||||
printLogoWidth(instance);
|
||||
++instance->state.keysHeight;
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
}
|
||||
|
||||
void ffPrintLogoAndKey(FFinstance* instance, const char* moduleName, uint8_t moduleIndex, const FFstrbuf* customKeyFormat)
|
||||
{
|
||||
ffPrintLogoLine(instance);
|
||||
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
|
||||
ffPrintColor(&instance->config.mainColor);
|
||||
|
||||
if(customKeyFormat == NULL || customKeyFormat->length == 0)
|
||||
{
|
||||
fputs(moduleName, stdout);
|
||||
|
||||
if(moduleIndex > 0)
|
||||
printf(" %hhu", moduleIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
FFstrbuf key;
|
||||
ffStrbufInit(&key);
|
||||
ffParseFormatString(&key, customKeyFormat, NULL, 1, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_UINT8, &moduleIndex}
|
||||
});
|
||||
ffStrbufWriteTo(&key, stdout);
|
||||
ffStrbufDestroy(&key);
|
||||
}
|
||||
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
ffStrbufWriteTo(&instance->config.separator, stdout);
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef FASTFETCH_INCLUDED_LOGO_logo
|
||||
#define FASTFETCH_INCLUDED_LOGO_logo
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
//logo.c
|
||||
void ffLogoPrint(FFinstance* instance, const char* data, bool doColorReplacement);
|
||||
|
||||
//builtin.c
|
||||
void ffLogoSetMainColor(FFinstance* instance);
|
||||
|
||||
void ffLogoPrintUnknown(FFinstance* instance);
|
||||
bool ffLogoPrintBuiltinIfExists(FFinstance* instance);
|
||||
void ffLogoPrintBuiltinDetected(FFinstance* instance);
|
||||
|
||||
//sixel/image.c
|
||||
bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type);
|
||||
|
||||
#endif
|
||||
+8
-8
@@ -39,10 +39,10 @@ void ffPrintCPU(FFinstance* instance)
|
||||
if(ffPrintFromCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpuKey, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS))
|
||||
return;
|
||||
|
||||
FILE* cpuinfo = fopen("/proc/cpuinfo", "r");
|
||||
FILE* cpuinfo = fopen(FASTFETCH_TARGET_DIR_ROOT"/proc/cpuinfo", "r");
|
||||
if(cpuinfo == NULL)
|
||||
{
|
||||
ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpuKey, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS, "fopen(\"/proc/cpuinfo\", \"r\") == NULL");
|
||||
ffPrintError(instance, FF_CPU_MODULE_NAME, 0, &instance->config.cpuKey, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS, "fopen(\""FASTFETCH_TARGET_DIR_ROOT"/proc/cpuinfo\", \"r\") == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -68,11 +68,11 @@ void ffPrintCPU(FFinstance* instance)
|
||||
break;
|
||||
|
||||
(void)(
|
||||
ffGetPropValue(line, "model name :", &name) ||
|
||||
ffGetPropValue(line, "vendor_id :", &vendor) ||
|
||||
ffGetPropValue(line, "cpu cores :", &physicalCoresString) ||
|
||||
ffGetPropValue(line, "cpu MHz :", &procGhzString) ||
|
||||
(name.length == 0 && ffGetPropValue(line, "Hardware :", &name)) //For Android devices
|
||||
ffParsePropLine(line, "model name :", &name) ||
|
||||
ffParsePropLine(line, "vendor_id :", &vendor) ||
|
||||
ffParsePropLine(line, "cpu cores :", &physicalCoresString) ||
|
||||
ffParsePropLine(line, "cpu MHz :", &procGhzString) ||
|
||||
(name.length == 0 && ffParsePropLine(line, "Hardware :", &name)) //For Android devices
|
||||
);
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ void ffPrintCPU(FFinstance* instance)
|
||||
if(ghz > 0)
|
||||
ffStrbufAppendF(&cpu, " @ %.9gGHz", ghz);
|
||||
|
||||
ffPrintAndSaveToCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpuKey, &cpu, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
ffPrintAndWriteToCache(instance, FF_CPU_MODULE_NAME, &instance->config.cpuKey, &cpu, &instance->config.cpuFormat, FF_CPU_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &name},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &namePretty},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &vendor},
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
void ffPrintCPUUsage(FFinstance* instance)
|
||||
{
|
||||
long user, nice, system, idle, iowait, irq, softirq;
|
||||
FILE* procStat = fopen("/proc/stat", "r");
|
||||
FILE* procStat = fopen(FASTFETCH_TARGET_DIR_ROOT"/proc/stat", "r");
|
||||
if(procStat == NULL)
|
||||
{
|
||||
ffPrintError(instance, FF_CPU_USAGE_MODULE_NAME, 0, &instance->config.cpuUsageKey, &instance->config.cpuUsageFormat, FF_CPU_USAGE_NUM_FORMAT_ARGS, "fopen(\"/proc/stat\", \"r\") == NULL");
|
||||
ffPrintError(instance, FF_CPU_USAGE_MODULE_NAME, 0, &instance->config.cpuUsageKey, &instance->config.cpuUsageFormat, FF_CPU_USAGE_NUM_FORMAT_ARGS, "fopen(\""FASTFETCH_TARGET_DIR_ROOT"/proc/stat\", \"r\") == NULL");
|
||||
return;
|
||||
}
|
||||
if (fscanf(procStat, "cpu%ld%ld%ld%ld%ld%ld%ld", &user, &nice, &system, &idle, &iowait, &irq, &softirq) < 0) goto exit;
|
||||
|
||||
@@ -147,7 +147,7 @@ static bool printCursorFromXDG(FFinstance* instance, bool user)
|
||||
if(user)
|
||||
ffParsePropFileHome(instance, ".icons/default/index.theme", "Inherits =", &theme);
|
||||
else
|
||||
ffParsePropFile("/usr/share/icons/default/index.theme", "Inherits =", &theme);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR"/share/icons/default/index.theme", "Inherits =", &theme);
|
||||
|
||||
if(theme.length == 0)
|
||||
{
|
||||
|
||||
+3
-4
@@ -79,18 +79,17 @@ void ffPrintDisk(FFinstance* instance)
|
||||
{
|
||||
if(instance->config.diskFolders.length == 0)
|
||||
{
|
||||
|
||||
struct statvfs fsRoot;
|
||||
int rootRet = statvfs("/", &fsRoot);
|
||||
|
||||
struct statvfs fsHome;
|
||||
int homeRet = statvfs("/home", &fsHome);
|
||||
int homeRet = statvfs(FASTFETCH_TARGET_DIR_HOME, &fsHome);
|
||||
|
||||
if(rootRet != 0 && homeRet != 0)
|
||||
{
|
||||
FF_STRBUF_CREATE(key);
|
||||
getKey(instance, &key, "", false);
|
||||
ffPrintError(instance, key.chars, 0, NULL, &instance->config.diskFormat, FF_DISK_NUM_FORMAT_ARGS, "statvfs failed for both / and /home");
|
||||
ffPrintError(instance, key.chars, 0, NULL, &instance->config.diskFormat, FF_DISK_NUM_FORMAT_ARGS, "statvfs failed for both / and " FASTFETCH_TARGET_DIR_HOME);
|
||||
ffStrbufDestroy(&key);
|
||||
return;
|
||||
}
|
||||
@@ -99,7 +98,7 @@ void ffPrintDisk(FFinstance* instance)
|
||||
printStatvfsCreateKey(instance, "/", &fsRoot);
|
||||
|
||||
if(homeRet == 0 && (rootRet != 0 || fsRoot.f_fsid != fsHome.f_fsid))
|
||||
printStatvfsCreateKey(instance, "/home", &fsHome);
|
||||
printStatvfsCreateKey(instance, FASTFETCH_TARGET_DIR_HOME, &fsHome);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ void ffPrintFont(FFinstance* instance)
|
||||
|
||||
FFstrbuf gtk;
|
||||
ffStrbufInitA(>k, 64);
|
||||
ffGetGtkPretty(>k, >k2.pretty, >k3.pretty, >k4.pretty);
|
||||
ffParseGTK(>k, >k2.pretty, >k3.pretty, >k4.pretty);
|
||||
|
||||
if(instance->config.fontFormat.length == 0)
|
||||
{
|
||||
|
||||
+2
-2
@@ -17,7 +17,7 @@ typedef struct GPUResult
|
||||
|
||||
static void vulkanFillGPUs(FFinstance* instance, FFlist* results)
|
||||
{
|
||||
FF_LIBRARY_LOAD(vulkan, instance->config.libVulkan, , "libvulkan.so", "libvulkan.so.1")
|
||||
FF_LIBRARY_LOAD(vulkan, instance->config.libVulkan, , "libvulkan.so", 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkCreateInstance,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkDestroyInstance,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(vulkan, vkEnumeratePhysicalDevices,)
|
||||
@@ -133,7 +133,7 @@ static void pciGetDriver(struct pci_dev* dev, FFstrbuf* driver, char*(*ffpci_get
|
||||
|
||||
static void pciFillGPUs(FFinstance* instance, FFlist* results)
|
||||
{
|
||||
FF_LIBRARY_LOAD(pci, instance->config.libPCI, , "libpci.so", "libpci.so.3")
|
||||
FF_LIBRARY_LOAD(pci, instance->config.libPCI, , "libpci.so", 4)
|
||||
FF_LIBRARY_LOAD_SYMBOL(pci, pci_alloc,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(pci, pci_init,)
|
||||
FF_LIBRARY_LOAD_SYMBOL(pci, pci_scan_bus,)
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ void ffPrintHost(FFinstance* instance)
|
||||
ffStrbufAppend(&host, &version);
|
||||
}
|
||||
|
||||
ffPrintAndSaveToCache(instance, FF_HOST_MODULE_NAME, &instance->config.hostKey, &host, &instance->config.hostFormat, FF_HOST_NUM_FORMAT_ARGS, (FFformatarg[]) {
|
||||
ffPrintAndWriteToCache(instance, FF_HOST_MODULE_NAME, &instance->config.hostKey, &host, &instance->config.hostFormat, FF_HOST_NUM_FORMAT_ARGS, (FFformatarg[]) {
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &family},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &name},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &version}
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ void ffPrintIcons(FFinstance* instance)
|
||||
}
|
||||
|
||||
FF_STRBUF_CREATE(gtkPretty);
|
||||
ffGetGtkPretty(>kPretty, gtk2, gtk3, gtk4);
|
||||
ffParseGTK(>kPretty, gtk2, gtk3, gtk4);
|
||||
|
||||
if(instance->config.iconsFormat.length == 0)
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ void ffPrintLocale(FFinstance* instance)
|
||||
FFstrbuf locale;
|
||||
ffStrbufInit(&locale);
|
||||
|
||||
ffParsePropFile("/etc/locale.conf", "LANG =", &locale);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/locale.conf", "LANG =", &locale);
|
||||
|
||||
if (locale.length == 0)
|
||||
getLocaleFromEnv(&locale);
|
||||
@@ -39,7 +39,7 @@ void ffPrintLocale(FFinstance* instance)
|
||||
return;
|
||||
}
|
||||
|
||||
ffPrintAndSaveToCache(instance, FF_LOCALE_MODULE_NAME, &instance->config.localeKey, &locale, &instance->config.localeFormat, FF_LOCALE_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
ffPrintAndWriteToCache(instance, FF_LOCALE_MODULE_NAME, &instance->config.localeKey, &locale, &instance->config.localeFormat, FF_LOCALE_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &locale}
|
||||
});
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
// Impl inspired by: https://github.com/sam-barr/paleofetch/blob/b7c58a52c0de39b53c9b5f417889a5886d324bfa/paleofetch.c#L544
|
||||
void ffPrintMemory(FFinstance* instance)
|
||||
{
|
||||
FILE* meminfo = fopen("/proc/meminfo", "r");
|
||||
FILE* meminfo = fopen(FASTFETCH_TARGET_DIR_ROOT"/proc/meminfo", "r");
|
||||
if(meminfo == NULL) {
|
||||
ffPrintError(instance, FF_MEMORY_MODULE_NAME, 0, &instance->config.memoryKey, &instance->config.memoryFormat, FF_MEMORY_NUM_FORMAT_ARGS, "fopen(\"/proc/meminfo\", \"r\") == NULL");
|
||||
ffPrintError(instance, FF_MEMORY_MODULE_NAME, 0, &instance->config.memoryKey, &instance->config.memoryFormat, FF_MEMORY_NUM_FORMAT_ARGS, "fopen(\""FASTFETCH_TARGET_DIR_ROOT"/proc/meminfo\", \"r\") == NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ void ffPrintMemory(FFinstance* instance)
|
||||
|
||||
if(used_mem == 0 && total_mem == 0 && percentage == 0)
|
||||
{
|
||||
ffPrintError(instance, FF_MEMORY_MODULE_NAME, 0, &instance->config.memoryKey, &instance->config.memoryFormat, FF_MEMORY_NUM_FORMAT_ARGS, "/proc/meminfo could't be parsed");
|
||||
ffPrintError(instance, FF_MEMORY_MODULE_NAME, 0, &instance->config.memoryKey, &instance->config.memoryFormat, FF_MEMORY_NUM_FORMAT_ARGS, FASTFETCH_TARGET_DIR_ROOT"/proc/meminfo could't be parsed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ void ffPrintOS(FFinstance* instance)
|
||||
ffStrbufAppendC(&os, ']');
|
||||
}
|
||||
|
||||
ffPrintAndSaveToCache(instance, FF_OS_MODULE_NAME, &instance->config.osKey, &os, &instance->config.osFormat, FF_OS_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
ffPrintAndWriteToCache(instance, FF_OS_MODULE_NAME, &instance->config.osKey, &os, &instance->config.osFormat, FF_OS_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->systemName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->name},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName},
|
||||
|
||||
+78
-15
@@ -14,7 +14,7 @@
|
||||
|
||||
static uint32_t getRpmPackageCount(FFinstance* instance)
|
||||
{
|
||||
FF_LIBRARY_LOAD(rpm, instance->config.librpm, 0, "librpm.so", "librpm.so.4")
|
||||
FF_LIBRARY_LOAD(rpm, instance->config.librpm, 0, "librpm.so", 5)
|
||||
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmReadConfigFiles, 0)
|
||||
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsCreate, 0)
|
||||
FF_LIBRARY_LOAD_SYMBOL(rpm, rpmtsInitIterator, 0)
|
||||
@@ -136,14 +136,52 @@ static uint32_t countFilesIn(const char* dirname, const char* filename)
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t getNixPackages(const FFstrbuf* path)
|
||||
{
|
||||
FFstrbuf output;
|
||||
ffStrbufInitA(&output, 128);
|
||||
|
||||
ffProcessAppendStdOut(&output, (char* const[]) {
|
||||
"nix-store",
|
||||
"-qR",
|
||||
path->chars,
|
||||
NULL
|
||||
});
|
||||
|
||||
//Each package is a new line in the output. If at least one line is found, add 1 for the last line.
|
||||
uint32_t result = ffStrbufCountC(&output, '\n');
|
||||
if(result > 0)
|
||||
result++;
|
||||
|
||||
ffStrbufDestroy(&output);
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t getNixPackagesDefault()
|
||||
{
|
||||
FFstrbuf path;
|
||||
ffStrbufInitA(&path, 64);
|
||||
ffStrbufAppendS(&path, FASTFETCH_TARGET_DIR_ROOT"/nix/var/nix/profiles/default");
|
||||
uint32_t result = getNixPackages(&path);
|
||||
ffStrbufDestroy(&path);
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t getNixPackagesUser(const FFinstance* instance)
|
||||
{
|
||||
FFstrbuf path;
|
||||
ffStrbufInitA(&path, 64);
|
||||
ffStrbufAppendS(&path, instance->state.passwd->pw_dir);
|
||||
ffStrbufAppendS(&path, "/.nix-profile");
|
||||
uint32_t result = getNixPackages(&path);
|
||||
ffStrbufDestroy(&path);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ffPrintPackages(FFinstance* instance)
|
||||
{
|
||||
uint32_t pacman = getNumElements("/var/lib/pacman/local", DT_DIR);
|
||||
uint32_t dpkg = getNumStrings("/var/lib/dpkg/status", "Status: ");
|
||||
|
||||
#if __ANDROID__
|
||||
dpkg += getNumStrings("/data/data/com.termux/files/usr/var/lib/dpkg/status", "Status: ");
|
||||
#endif
|
||||
uint32_t pacman = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/var/lib/pacman/local", DT_DIR);
|
||||
uint32_t dpkg = getNumStrings(FASTFETCH_TARGET_DIR_ROOT"/var/lib/dpkg/status", "Status: ");
|
||||
|
||||
#ifdef FF_HAVE_RPM
|
||||
uint32_t rpm = getRpmPackageCount(instance);
|
||||
@@ -151,16 +189,27 @@ void ffPrintPackages(FFinstance* instance)
|
||||
uint32_t rpm = 0;
|
||||
#endif
|
||||
|
||||
uint32_t emerge = countFilesIn("/var/db/pkg", "SIZE");
|
||||
uint32_t xbps = getNumElements("/var/db/xbps", DT_REG);
|
||||
uint32_t flatpak = getNumElements("/var/lib/flatpak/app", DT_DIR);
|
||||
uint32_t snap = getNumElements("/snap", DT_DIR);
|
||||
uint32_t emerge = countFilesIn(FASTFETCH_TARGET_DIR_ROOT"/var/db/pkg", "SIZE");
|
||||
uint32_t xbps = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/var/db/xbps", DT_REG);
|
||||
|
||||
uint32_t nixUser = 0;
|
||||
uint32_t nixDefault = 0;
|
||||
|
||||
//Nix detection is kinda slow, so we only do it if the nix dir exists
|
||||
if(ffFileExists(FASTFETCH_TARGET_DIR_ROOT"/nix", S_IFDIR))
|
||||
{
|
||||
nixUser = getNixPackagesUser(instance);
|
||||
nixDefault = getNixPackagesDefault();
|
||||
}
|
||||
|
||||
uint32_t flatpak = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/var/lib/flatpak/app", DT_DIR);
|
||||
uint32_t snap = getNumElements(FASTFETCH_TARGET_DIR_ROOT"/snap", DT_DIR);
|
||||
|
||||
//Accounting for the /snap/bin folder
|
||||
if(snap > 0)
|
||||
--snap;
|
||||
|
||||
uint32_t all = pacman + dpkg + rpm + emerge + xbps + flatpak + snap;
|
||||
uint32_t all = pacman + dpkg + rpm + emerge + xbps + nixUser + nixDefault + flatpak + snap;
|
||||
|
||||
if(all == 0)
|
||||
{
|
||||
@@ -170,12 +219,12 @@ void ffPrintPackages(FFinstance* instance)
|
||||
|
||||
FFstrbuf manjaroBranch;
|
||||
ffStrbufInit(&manjaroBranch);
|
||||
if(ffParsePropFile("/etc/pacman-mirrors.conf", "Branch =", &manjaroBranch) && manjaroBranch.length == 0)
|
||||
if(ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/pacman-mirrors.conf", "Branch =", &manjaroBranch) && manjaroBranch.length == 0)
|
||||
ffStrbufSetS(&manjaroBranch, "stable");
|
||||
|
||||
if(instance->config.packagesFormat.length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, FF_PACKAGES_MODULE_NAME, 0, &instance->config.batteryKey);
|
||||
ffPrintLogoAndKey(instance, FF_PACKAGES_MODULE_NAME, 0, &instance->config.packagesKey);
|
||||
|
||||
#define FF_PRINT_PACKAGE(name) \
|
||||
if(name > 0) \
|
||||
@@ -197,7 +246,21 @@ void ffPrintPackages(FFinstance* instance)
|
||||
FF_PRINT_PACKAGE(dpkg)
|
||||
FF_PRINT_PACKAGE(rpm)
|
||||
FF_PRINT_PACKAGE(emerge)
|
||||
FF_PRINT_PACKAGE(xbps)
|
||||
|
||||
if(nixUser > 0)
|
||||
{
|
||||
printf("%u (nix-user)", nixUser);
|
||||
if((all = all - nixUser) > 0)
|
||||
printf(", ");
|
||||
}
|
||||
|
||||
if(nixDefault > 0)
|
||||
{
|
||||
printf("%u (nix-default)", nixDefault);
|
||||
if((all = all - nixDefault) > 0)
|
||||
printf(", ");
|
||||
}
|
||||
|
||||
FF_PRINT_PACKAGE(flatpak)
|
||||
FF_PRINT_PACKAGE(snap)
|
||||
|
||||
|
||||
+42
-3
@@ -1,7 +1,9 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#define FF_PLAYER_MODULE_NAME "Media Player"
|
||||
#define FF_PLAYER_NUM_FORMAT_ARGS 1
|
||||
#define FF_PLAYER_NUM_FORMAT_ARGS 3
|
||||
|
||||
void ffPrintPlayer(FFinstance* instance)
|
||||
{
|
||||
@@ -13,15 +15,52 @@ void ffPrintPlayer(FFinstance* instance)
|
||||
return;
|
||||
}
|
||||
|
||||
FFstrbuf playerPretty;
|
||||
ffStrbufInit(&playerPretty);
|
||||
|
||||
//If we are on a website, prepend the website name
|
||||
if(ffStrbufStartsWithS(&media->url, "https://www."))
|
||||
ffStrbufAppendS(&playerPretty, media->url.chars + 12);
|
||||
else if(ffStrbufStartsWithS(&media->url, "http://www."))
|
||||
ffStrbufAppendS(&playerPretty, media->url.chars + 11);
|
||||
else if(ffStrbufStartsWithS(&media->url, "https://"))
|
||||
ffStrbufAppendS(&playerPretty, media->url.chars + 8);
|
||||
else if(ffStrbufStartsWithS(&media->url, "http://"))
|
||||
ffStrbufAppendS(&playerPretty, media->url.chars + 7);
|
||||
|
||||
//If we found a website name, make it more pretty
|
||||
if(playerPretty.length > 0)
|
||||
{
|
||||
ffStrbufSubstrBeforeFirstC(&playerPretty, '/'); //Remove the path
|
||||
ffStrbufSubstrBeforeLastC(&playerPretty, '.'); //Remove the TLD
|
||||
}
|
||||
|
||||
//Check again for length, as we may have removed everything.
|
||||
bool playerPrettyIsCustom = playerPretty.length > 0;
|
||||
|
||||
//If we don't have subdomains, it is usually more pretty to capitalize the first letter.
|
||||
if(playerPrettyIsCustom && ffStrbufFirstIndexC(&playerPretty, '.') == playerPretty.length)
|
||||
playerPretty.chars[0] = (char) toupper(playerPretty.chars[0]);
|
||||
|
||||
if(playerPrettyIsCustom)
|
||||
ffStrbufAppendS(&playerPretty, " (");
|
||||
|
||||
ffStrbufAppend(&playerPretty, &media->player);
|
||||
|
||||
if(playerPrettyIsCustom)
|
||||
ffStrbufAppendC(&playerPretty, ')');
|
||||
|
||||
if(instance->config.playerFormat.length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(instance, FF_PLAYER_MODULE_NAME, 0, &instance->config.playerKey);
|
||||
ffStrbufPutTo(&media->player, stdout);
|
||||
ffStrbufPutTo(&playerPretty, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormatString(instance, FF_PLAYER_MODULE_NAME, 0, &instance->config.playerKey, &instance->config.playerFormat, NULL, FF_PLAYER_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &media->player}
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &playerPretty},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &media->player},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &media->busNameShort}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+73
-6
@@ -1,7 +1,44 @@
|
||||
#include "fastfetch.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#define FF_SONG_MODULE_NAME "Song"
|
||||
#define FF_SONG_NUM_FORMAT_ARGS 3
|
||||
#define FF_SONG_NUM_FORMAT_ARGS 5
|
||||
|
||||
static bool shouldIgoreChar(char c)
|
||||
{
|
||||
return isblank(c) || c == '-' || c == '.';
|
||||
}
|
||||
|
||||
static bool artistInSongTitle(const FFstrbuf* song, const FFstrbuf* artist)
|
||||
{
|
||||
uint32_t artistIndex = 0;
|
||||
uint32_t songIndex = 0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
while(shouldIgoreChar(song->chars[songIndex]))
|
||||
++songIndex;
|
||||
|
||||
while(shouldIgoreChar(artist->chars[artistIndex]))
|
||||
++artistIndex;
|
||||
|
||||
if(artist->chars[artistIndex] == '\0')
|
||||
return true;
|
||||
|
||||
if(song->chars[songIndex] == '\0')
|
||||
return false;
|
||||
|
||||
if(tolower(song->chars[songIndex]) != tolower(artist->chars[artistIndex]))
|
||||
return false;
|
||||
|
||||
++artistIndex;
|
||||
++songIndex;
|
||||
}
|
||||
|
||||
//Unreachable
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffPrintSong(FFinstance* instance)
|
||||
{
|
||||
@@ -13,30 +50,60 @@ void ffPrintSong(FFinstance* instance)
|
||||
return;
|
||||
}
|
||||
|
||||
FFstrbuf songPretty;
|
||||
ffStrbufInitCopy(&songPretty, &media->song);
|
||||
const char* removeStrings[] = {
|
||||
"(Official Music Video)", "(Official Video)", "(Music Video)",
|
||||
"[Official Music Video]", "[Official Video]", "[Music Video]",
|
||||
"| Official Music Video", "| Official Video", "| Music Video",
|
||||
"[Official Audio]", "[Audio]", "(Audio)", "| Official Audio", "| Audio", "| OFFICIAL AUDIO",
|
||||
"(Lyric Video)", "(Official Lyric Video)", "(Lyrics)",
|
||||
"[Lyric Video]", "[Official Lyric Video]", "[Lyrics]",
|
||||
"| Lyric Video", "| Official Lyric Video", "| Lyrics",
|
||||
};
|
||||
ffStrbufRemoveStringsA(&songPretty, sizeof(removeStrings) / sizeof(removeStrings[0]), removeStrings);
|
||||
ffStrbufTrimRight(&songPretty, ' ');
|
||||
|
||||
if(songPretty.length == 0)
|
||||
ffStrbufAppend(&songPretty, &media->song);
|
||||
|
||||
if(instance->config.songFormat.length == 0)
|
||||
{
|
||||
//We don't expose artistPretty to the format, as it might be empty (when the think that the artist is already in the song title)
|
||||
FFstrbuf artistPretty;
|
||||
ffStrbufInitCopy(&artistPretty, &media->artist);
|
||||
ffStrbufRemoveIgnCaseEndS(&artistPretty, " - Topic");
|
||||
ffStrbufRemoveIgnCaseEndS(&artistPretty, "VEVO");
|
||||
ffStrbufTrimRight(&artistPretty, ' ');
|
||||
|
||||
if(artistInSongTitle(&songPretty, &artistPretty))
|
||||
ffStrbufClear(&artistPretty);
|
||||
|
||||
ffPrintLogoAndKey(instance, FF_SONG_MODULE_NAME, 0, &instance->config.songKey);
|
||||
|
||||
if(media->artist.length > 0)
|
||||
if(artistPretty.length > 0)
|
||||
{
|
||||
ffStrbufWriteTo(&media->artist, stdout);
|
||||
ffStrbufWriteTo(&artistPretty, stdout);
|
||||
fputs(" - ", stdout);
|
||||
}
|
||||
|
||||
if(media->album.length > 0)
|
||||
//Some sites (e.g. reddit) expose their url as album. We don't want to show that
|
||||
if(media->album.length > 0 && !ffStrbufStartsWithIgnCaseS(&media->album, "http"))
|
||||
{
|
||||
ffStrbufWriteTo(&media->album, stdout);
|
||||
fputs(" - ", stdout);
|
||||
}
|
||||
|
||||
ffStrbufPutTo(&media->song, stdout);
|
||||
ffStrbufPutTo(&songPretty, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormatString(instance, FF_SONG_MODULE_NAME, 0, &instance->config.songKey, &instance->config.songFormat, NULL, FF_SONG_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &songPretty},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &media->song},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &media->artist},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &media->album}
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &media->album},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &media->url}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ static void printTTY(FFinstance* instance)
|
||||
FFstrbuf fontName;
|
||||
ffStrbufInit(&fontName);
|
||||
|
||||
ffParsePropFile("/etc/vconsole.conf", "Font =", &fontName);
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_ROOT"/etc/vconsole.conf", "Font =", &fontName);
|
||||
|
||||
if(fontName.length == 0)
|
||||
{
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ void ffPrintTheme(FFinstance* instance)
|
||||
ffStrbufTrim(&plasmaColorPretty, ' ');
|
||||
|
||||
FF_STRBUF_CREATE(gtkPretty);
|
||||
ffGetGtkPretty(>kPretty, gtk2, gtk3, gtk4);
|
||||
ffParseGTK(>kPretty, gtk2, gtk3, gtk4);
|
||||
|
||||
if(instance->config.themeFormat.length == 0)
|
||||
{
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ const FFTitleResult* ffDetectTitle(FFinstance* instance)
|
||||
static inline void printTitlePart(FFinstance* instance, const FFstrbuf* content)
|
||||
{
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_BOLT, stdout);
|
||||
ffPrintColor(&instance->config.color);
|
||||
ffPrintColor(&instance->config.mainColor);
|
||||
ffStrbufWriteTo(content, stdout);
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
}
|
||||
|
||||
@@ -495,6 +495,17 @@ bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end)
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
for(uint32_t i = 0; i < strbuf->length; i++)
|
||||
{
|
||||
if(strbuf->chars[i] == c)
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool testEndsWithIgnCaseS(const FFstrbuf* strbuf, const char* end, uint32_t* endLength)
|
||||
{
|
||||
*endLength = (uint32_t) strlen(end);
|
||||
|
||||
@@ -87,6 +87,8 @@ bool ffStrbufStartsWithIgnCaseS(const FFstrbuf* strbuf, const char* start);
|
||||
bool ffStrbufEndsWithC(const FFstrbuf* strbuf, char c);
|
||||
bool ffStrbufEndsWithS(const FFstrbuf* strbuf, const char* end);
|
||||
|
||||
uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c);
|
||||
|
||||
bool ffStrbufRemoveIgnCaseEndS(FFstrbuf* strbuf, const char* end);
|
||||
|
||||
void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file);
|
||||
|
||||
+10
-6
@@ -25,12 +25,6 @@ int main(int argc, char** argv)
|
||||
ffInitInstance(&instance);
|
||||
)
|
||||
|
||||
FASTFETCH_TEST_PERFORMANCE(
|
||||
puts("Configuration");
|
||||
ffLoadLogo(&instance);
|
||||
)
|
||||
|
||||
ffStrbufSet(&instance.config.color, &instance.config.logoColors[0]);
|
||||
instance.config.showErrors = true;
|
||||
instance.config.recache = argc == 1;
|
||||
instance.config.cacheSave = false;
|
||||
@@ -41,6 +35,11 @@ int main(int argc, char** argv)
|
||||
ffStartDetectionThreads(&instance);
|
||||
)
|
||||
|
||||
FASTFETCH_TEST_PERFORMANCE(
|
||||
puts("Starting");
|
||||
ffStart(&instance);
|
||||
)
|
||||
|
||||
FASTFETCH_TEST_PERFORMANCE(ffPrintTitle(&instance))
|
||||
FASTFETCH_TEST_PERFORMANCE(ffPrintSeparator(&instance))
|
||||
FASTFETCH_TEST_PERFORMANCE(ffPrintOS(&instance))
|
||||
@@ -74,5 +73,10 @@ int main(int argc, char** argv)
|
||||
FASTFETCH_TEST_PERFORMANCE(ffPrintBreak(&instance))
|
||||
FASTFETCH_TEST_PERFORMANCE(ffPrintColors(&instance))
|
||||
|
||||
FASTFETCH_TEST_PERFORMANCE(
|
||||
puts("Finishing");
|
||||
ffFinish(&instance);
|
||||
)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user