Compare commits

...

174 Commits

Author SHA1 Message Date
Carter Li ea162fd452 Merge pull request #734 from fastfetch-cli/dev
Release: v2.8.4
2024-02-23 16:09:51 +08:00
李通洲 b80391b183 Release: v2.8.4 2024-02-23 15:56:12 +08:00
李通洲 4c7a9e4394 Doc: update changelog 2024-02-23 10:01:05 +08:00
李通洲 4b747f70a4 Disk (Linux): ensure only physical devices are detected
Ref: https://github.com/fastfetch-cli/fastfetch/issues/731#issuecomment-1955814211
2024-02-23 09:29:39 +08:00
李通洲 5fb4b6dc04 Display: --display-compact-type support *-with-refresh-rate
Ref: https://github.com/fastfetch-cli/fastfetch/discussions/732
2024-02-22 18:45:57 +08:00
李通洲 5e7cfe2976 Display: add option --display-order 2024-02-22 10:47:13 +08:00
李通洲 77db2d84a3 FFstrbuf: remove ffStrbufCompAlphabetically 2024-02-22 10:38:33 +08:00
李通洲 15bb5bfb24 Packages: add ability to disable specified package manager
Fix #729
2024-02-22 10:03:38 +08:00
李通洲 4e9ee9aa03 Package: code cleanup 2024-02-21 15:40:04 +08:00
李通洲 6a0c7ca788 Disk (Linux): try fixing multidevice bcachefs filesystem compatibility
Ref: #731
2024-02-21 09:05:26 +08:00
李通洲 90e99bcf69 Doc: fix invalid commands 2024-02-21 09:05:26 +08:00
Lenny0939 5b20a86d53 Fix mistake in README.md (#730)
Sudo is not necessary to use nix-shell, and puts you in a shell as root which is not ideal
2024-02-20 18:42:59 -06:00
李通洲 6ad1262f4a NetIO: add option --netio-detect-total 2024-02-20 14:44:55 +08:00
李通洲 e0297e1dd1 DiskIO: add option --diskio-detect-total 2024-02-20 14:43:50 +08:00
李通洲 937611aa29 Colors: support JSON config generation 2024-02-15 22:05:34 +08:00
李通洲 eda38e16db Colors: don't print extra empty lines 2024-02-15 21:55:33 +08:00
李通洲 2731756c39 Platform (Windows): small optimization 2024-02-15 20:29:57 +08:00
李通洲 853ca0f608 Platform (Windows): don't assume x86 as i686 2024-02-15 20:29:34 +08:00
李通洲 17f4a6e055 Colors: support block related settings
Fix #721
2024-02-14 22:09:12 +08:00
李通洲 925dc6f681 TerminalFont (Windows): support portable Windows Terminal settings
Fix #720
2024-02-13 19:49:49 +08:00
李通洲 706527eab4 Github: update ISSUE_TEMPLATE 2024-02-13 19:19:29 +08:00
李通洲 3a96ade423 CPU (Linux): don't segfault if we fail to find Vendor ID in lscpu
Fix #718
2024-02-13 19:08:44 +08:00
李通洲 da9c928286 CMake: make artifact file names consistant
Fix #719
2024-02-13 19:02:03 +08:00
Carter Li 30d3d00900 Merge pull request #717 from fastfetch-cli/dev
Release v2.8.3
2024-02-12 10:59:30 +08:00
李通洲 99fce80d0d CI: fix windows artifacts generation 2024-02-12 10:46:57 +08:00
Herby Gillot a5a28e30a0 README: add MacPorts install info (#716)
Add info on installing `fastfetch` on macOS via MacPorts: https://ports.macports.org/port/fastfetch/
2024-02-12 10:43:23 +08:00
李通洲 7fe39353df Release: v2.8.3 2024-02-12 10:28:29 +08:00
李通洲 a3576b3154 CI: release file name without version
Fix #714
2024-02-12 10:28:29 +08:00
AlbydS c5d0d84001 Add installation instructions for even more Linux distributions (#715)
Added Alpine (now with the right command), ALT Linux and Arch AUR to the installation instructions.
2024-02-12 10:20:10 +08:00
李通洲 467ed54a3b GPU (Linux): lazy load pci.ids 2024-02-12 10:12:34 +08:00
Carter 7ea8882843 GPU (FreeBSD): detect correct AMD card names 2024-02-12 18:09:11 +08:00
李通洲 f4cb3bb33f GPU (Linux): use amdgpu.ids 2024-02-12 00:43:06 +08:00
李通洲 330eb9fa21 GPU: show sub-device if available
Try fixing #713
2024-02-11 23:01:14 +08:00
李通洲 1006f513f5 Release: v2.8.2 2024-02-10 14:38:47 +08:00
李通洲 652c4b2e82 CI: don't upload old artifacts 2024-02-10 14:37:27 +08:00
李通洲 3c618a8cd0 Merge remote-tracking branch 'upstream/master' into dev 2024-02-10 14:14:09 +08:00
李通洲 b5821de793 Release: v2.8.1 2024-02-10 14:02:22 +08:00
李通洲 dec604691c CMake: try fixing packaging name conflicting 2024-02-10 13:59:34 +08:00
Carter Li 72baa6cca9 Merge pull request #712 from fastfetch-cli/dev
Release v2.8.0
2024-02-10 12:02:58 +08:00
李通洲 34b023a74f Release: 2.8.0 (ci skip)
For Luna New Year!
2024-02-10 10:32:14 +08:00
李通洲 8249a8ed6a Doc: update changelog 2024-02-09 00:10:29 +08:00
李通洲 7e1ac5e24a Terminal (Windows): code cleanup 2024-02-08 23:15:58 +08:00
李通洲 55c72a8bb3 Camera (Windows): fix Windows Server Core compatibility 2024-02-08 19:14:09 +08:00
Carter Li b602bb20c2 Battery (Linux): print the same format of battery status as other platforms 2024-02-08 14:10:51 +08:00
Carter Li 46ed24275f Battery (FreeBSD): fix typos 2024-02-08 13:59:02 +08:00
Carter Li 71db83f806 PowerAdapter (Linux): don't print not connected either
To align result to macOS
2024-02-08 13:51:30 +08:00
李通洲 0746afa0c2 PowerAdapter (macOS): don't show not connected if no power adapter is detected 2024-02-08 10:53:58 +08:00
李通洲 805c384819 Battery (macOS): don't show an empty battery if no battery is detected 2024-02-08 10:37:06 +08:00
Carter Li 9e4c0e318c Chore: add dpkg related stuff 2024-02-07 14:39:19 +08:00
李通洲 51eaac2fd7 Doc: update changelog 2024-02-06 09:54:33 +08:00
李通洲 92c3df82e6 Logo (Builtin): add PikaOS
Ref: https://github.com/hykilpikonna/hyfetch/pull/231
2024-02-06 09:30:24 +08:00
李通洲 7f238a701e Logo (Builtin): add tatra
Ref: https://github.com/dylanaraps/neofetch/pull/2439
2024-02-06 09:25:44 +08:00
李通洲 72236f62ad Logo (Builtin): add z/OS
Ref: https://github.com/dylanaraps/neofetch/pull/2436
2024-02-06 09:03:01 +08:00
李通洲 51b0c43d76 Platform (Windows): use %USERNAME% if available 2024-02-05 20:01:19 +08:00
李通洲 79e2007d30 Revert "Platform (Linux): use $HOSTNAME if available"
$HOSTNAME doesn't seem to be a standard variable

This reverts commit 02eb604ceb.
2024-02-05 20:01:18 +08:00
李通洲 02eb604ceb Platform (Linux): use $HOSTNAME if available
Ref: #710
2024-02-05 18:23:21 +08:00
李通洲 ce6b2b85f7 Locale (Linux): use environment variable if available
In some machine `setlocale(LC_MESSAGES, NULL)` returns `C` for some reason.
2024-02-05 16:25:12 +08:00
李通洲 48d1980061 CI: build linux old 2024-02-05 14:32:17 +08:00
李通洲 40fae5c5f1 Camera (Android): add empty color space result 2024-02-04 19:07:47 +08:00
李通洲 e296ee1040 CI (Linux): bump version of linux runners
Drop support of Debian 11
2024-02-04 15:48:58 +08:00
李通洲 199e71553d CI: run camera module 2024-02-04 15:14:18 +08:00
李通洲 13fa218e5a Camera: adjust output format 2024-02-04 14:17:18 +08:00
李通洲 eed5efabea Camera (Windows): detect color space 2024-02-04 14:17:18 +08:00
李通洲 d2315e967e Camera (macOS): detect color space 2024-02-04 14:17:18 +08:00
Carter Li cbe3c70480 Camera (Linux): add property colorspace 2024-02-04 14:17:18 +08:00
李通洲 c918226909 Fastfetch: print videodev2 in --list-features 2024-02-04 09:56:22 +08:00
李通洲 18472660ae CI (FreeBSD): remove unused depenencies 2024-02-04 09:27:04 +08:00
李通洲 458c2ccd01 Camera (FreeBSD): enable support
Requires build dependency `v4l_compat`
2024-02-04 09:26:19 +08:00
李通洲 7bb9efcebb Camera (Android): init support 2024-02-02 23:22:40 +08:00
李通洲 8a42dfd68d Camera: tidy; add module to all.jsonc 2024-02-02 22:43:01 +08:00
李通洲 3edd8a6740 Camera (Linux): init support 2024-02-02 22:14:25 +08:00
李通洲 cba22b7155 Camera (Windows): init support 2024-02-02 20:36:22 +08:00
李通洲 246ad6d288 Sound (Windows): tidy 2024-02-02 20:36:22 +08:00
李通洲 295e119810 Camera (macOS): new module 2024-02-02 20:36:22 +08:00
李通洲 cfe22f9524 Terminal (Linux): try fixing #707 (v2) 2024-02-01 17:56:40 +08:00
李通洲 de2c1d7786 CI: unify artifacts name (v2) 2024-02-01 16:00:33 +08:00
李通洲 7d74339aa0 CI: build in parallel 2024-02-01 15:43:56 +08:00
李通洲 7589e962c2 CI: unify artifact names 2024-02-01 15:25:05 +08:00
李通洲 9a189694f9 CI: silence more warnings 2024-02-01 15:24:07 +08:00
李通洲 4069fbfe7b CI: upgrade codeql-action 2024-02-01 15:02:37 +08:00
李通洲 7ccd886909 CI: build aarch64 binaries 2024-02-01 14:29:28 +08:00
李通洲 42957356b2 GPU: remove libpci related stuff 2024-02-01 13:38:15 +08:00
李通洲 9038cd32b2 Terminal (Linux): don't assume blackbox is build for flatpak 2024-02-01 09:14:06 +08:00
李通洲 128c3bfea6 TerminalShell (Linux): try supporting blackbox
Fix #707
2024-02-01 09:02:49 +08:00
李通洲 60ed822f6a GPU (Linux): fix detection in some cases 2024-01-31 18:58:48 +08:00
Carter Li 527ec1bc61 Logo (Builtin): add asahi2; make asahi logo actually work 2024-01-31 16:47:22 +08:00
Carter Li cbf203901b CPU (Linux): code refactor 2024-01-31 14:36:00 +08:00
Carter Li cf6f3dbe0c CI (Windows): fix build 2024-01-31 13:35:57 +08:00
Carter Li ab625497ce CPU (Linux): code refactor 2024-01-31 13:28:18 +08:00
Yussef Dalton 83532b68dd CPU (Linux): use marketing name on Asahi Linux 2024-01-31 11:02:41 +08:00
Carter Li cd2a1495b8 GPU (FreeBSD): use ffGPUParsePciIds 2024-01-31 10:39:09 +08:00
Carter Li b01d2bdd8c GPU (Linux): rewrite; drop libpci dependency 2024-01-31 10:20:49 +08:00
Carter Li 736d5316cc Merge pull request #705 from fastfetch-cli/dev
Release v2.7.1
2024-01-30 19:25:55 +08:00
李通洲 efe42a2c7d GPU: fix a copy-paste error 2024-01-30 18:54:26 +08:00
李通洲 ee07755139 Release: v2.7.1 2024-01-30 18:45:56 +08:00
李通洲 3d924eeadd Merge remote-tracking branch 'upstream/master' into dev 2024-01-30 18:27:24 +08:00
李通洲 aaa091f23b Terminal (Linux): fix segfault 2024-01-30 15:22:26 +08:00
李通洲 53cd1e5378 DateTime: print timezone info; simplify code 2024-01-29 22:01:54 +08:00
李通洲 3747683f0d GPU: add vendor code of QTI & MTK 2024-01-29 21:49:42 +08:00
李通洲 59c1e3d8c5 Platform: detect real path of exe path 2024-01-28 10:45:21 +08:00
Carter Li 1206f6d2ba Merge pull request #701 from fastfetch-cli/dev
Release v2.7.0
2024-01-26 11:06:32 +08:00
李通洲 9aad3e339a CMake: remove unused deps 2024-01-26 10:44:20 +08:00
李通洲 ef9221f305 CI: generate sha512sums [no ci] 2024-01-26 10:41:31 +08:00
李通洲 391a3a0430 Release: v2.7.0
Bump minor version because of rewriting the FreeBSD GPU detection code
2024-01-26 10:23:44 +08:00
李通洲 6b0314f14b Platform: fix exe path detection 2024-01-26 10:19:21 +08:00
李通洲 8e316eb080 Release: v2.6.4 2024-01-26 10:10:11 +08:00
李通洲 999f2170fe Terminal: ignore sshd 2024-01-26 09:53:12 +08:00
李通洲 0282b884cc OpenCL: fix possible segfaults
Found in Alpine Linux
2024-01-26 09:38:08 +08:00
李通洲 ef7e6d0a6a GPU (WSL): fix uninitialized variables 2024-01-26 09:20:58 +08:00
李通洲 77253a8d81 GPU (FreeBSD): better name detection 2024-01-26 09:20:58 +08:00
Carter Li 2041272f5f GPU (Linux): simpify code 2024-01-25 18:32:40 +08:00
Carter Li d2a41bdfe1 GPU (FreeBSD): drop pciutils dep 2024-01-25 10:33:06 +08:00
Carter Li 025a708ecb Shell: remove trailing \0 in JSON output 2024-01-25 10:33:06 +08:00
John Mertz 4e2c124442 ASCII logos for fedora immutable variants (#700)
Container Linux is also deprecated and continued as Fedora CoreOS
2024-01-23 23:38:41 -06:00
李通洲 79ba9d7a68 TerminalShell (Linux): fix segfault 2024-01-23 18:51:00 +08:00
李通洲 ee60ec3530 TerminalShell: don't detect sh as a terminal 2024-01-23 16:38:43 +08:00
李通洲 9d7cbb0fe3 Revert "3rdparty: use a newer wcwidch implementation"
Unwanted change

This reverts commit 28ea765f19.
2024-01-23 14:42:00 +08:00
李通洲 0b98a14977 Fastfetch: don't expand envs in --config
Since it can only be used in command line
2024-01-23 13:14:53 +08:00
李通洲 8f51763374 Linux: allow command substitution when expanding paths
Ref: https://github.com/fastfetch-cli/fastfetch/discussions/698
2024-01-23 13:13:30 +08:00
李通洲 28ea765f19 3rdparty: use a newer wcwidch implementation 2024-01-23 10:19:02 +08:00
李通洲 5378d05bfb Doc: update changelog 2024-01-22 19:33:27 +08:00
李通洲 bbf04f0d40 Doc: add TerminalTheme 2024-01-22 18:50:11 +08:00
李通洲 ec6195133b TerminalTheme: add new module 2024-01-22 16:40:27 +08:00
李通洲 fa8c99601c TerminalSize: tidy 2024-01-22 14:34:19 +08:00
李通洲 a5d5de90f8 Terminal (Linux): support screen version detection 2024-01-22 14:33:55 +08:00
李通洲 994fd359a5 Terminal (Linux): fix kgx version detection 2024-01-22 11:10:40 +08:00
李通洲 a9a5790cba TerminalShell (Linux): improve terminal detection by env 2024-01-22 11:10:40 +08:00
李通洲 31b3fe403a Wifi (Linux): remove trailing \n
Fix #697
2024-01-22 11:10:30 +08:00
李通洲 14b74fe51d Doc: update issue template 2024-01-22 09:10:03 +08:00
Carter Li 35a5a03cd7 Merge pull request #696 from fastfetch-cli/dev
Release v2.6.3
2024-01-21 23:04:15 +08:00
李通洲 f927b8ea87 Release: v2.6.3 2024-01-21 23:01:49 +08:00
李通洲 ebefcec3e2 Bluetooth: fix result printing 2024-01-21 23:00:38 +08:00
Carter Li c151bf0b37 Merge pull request #695 from fastfetch-cli/dev
Release v2.6.2
2024-01-21 17:54:12 +08:00
李通洲 a767104b96 TerminalShell (Windows): more variable initialization fixes 2024-01-21 17:52:03 +08:00
Carter Li 18fced9b2e Merge pull request #694 from fastfetch-cli/dev
Release 2.6.2
2024-01-21 17:46:02 +08:00
李通洲 713ef0ce34 Release: v2.6.2 2024-01-21 17:41:34 +08:00
李通洲 5b2db02bc1 CI: Fix building for GCC in Windows 2024-01-21 17:39:31 +08:00
Carter Li 0f69dc5980 Merge pull request #692 from fastfetch-cli/dev
Release 2.6.1
2024-01-20 22:34:06 +08:00
李通洲 6af57ff5b6 Doc: update changelog 2024-01-20 22:20:28 +08:00
Carter Li 7d7789565b PowerAdapter (macOS): improve detection for Intel macbook 2024-01-20 21:46:57 +08:00
Carter Li 0eb76e9636 Battery (macOS): improve manufacture info detection 2024-01-20 21:38:24 +08:00
李通洲 8b1ee64a3e GPU (macOS): fix gpu type detection 2024-01-20 20:57:33 +08:00
李通洲 b0acf168bf Doc: update changelog 2024-01-20 20:14:56 +08:00
李通洲 7ddc207574 Percentage: add options --percent-color-* 2024-01-20 20:06:42 +08:00
李通洲 d1a791b333 Global: make threshold of percentage colors configurable
Fix #689
2024-01-20 18:40:12 +08:00
李通洲 62ca495155 Percentage: prepare to make threshold configurable 2024-01-20 14:10:56 +08:00
李通洲 e7974a7cea Percentage: refactor function names 2024-01-20 13:49:04 +08:00
李通洲 24cb83dd18 Bluetooth / Gamepad / Sound: support percentage number formatting 2024-01-20 13:48:42 +08:00
李通洲 da5c44b3d0 Percentage: simplify usage of ffAppendPercentBar 2024-01-20 13:27:55 +08:00
李通洲 bd71aa931f Global: rename common/bar to common/percent 2024-01-20 11:28:38 +08:00
李通洲 4d1f242e1d Terminal (Windows): tidy 2024-01-19 22:23:32 +08:00
李通洲 d810245d55 Doc: update changelog 2024-01-19 21:54:44 +08:00
李通洲 06181ec433 Terminal (Windows): default default terminal to conhost 2024-01-19 21:54:44 +08:00
李通洲 8404ae034f Locale: improve detection
Linux: always use `setlocale`, fix #688
Windows: don't append `UTF-8`
2024-01-19 21:15:05 +08:00
李通洲 8e7d465333 Fastfetch: create sub folders when writing config file
Fix #690
2024-01-19 21:01:02 +08:00
李通洲 87813b3306 Shell: detect associated TTY 2024-01-19 16:43:08 +08:00
李通洲 9610a1ab23 TerminalShell (Windows): simplify nested shell detection by looking up GUI objects 2024-01-19 15:00:10 +08:00
李通洲 5f14781970 TerminalShell (Windows): set exePath 2024-01-19 14:40:07 +08:00
Carter Li 356488be0c TerminalShell (FreeBSD): detect real exe path 2024-01-19 14:40:07 +08:00
Carter Li e013c87890 TerminalShell (Linux): detect real exe path 2024-01-19 14:40:07 +08:00
李通洲 7d78d92a92 TerminalShell (macOS): detect full exe path 2024-01-19 14:40:07 +08:00
李通洲 06af39835a Terminal: don't use login as terminal process; set ppid 2024-01-19 14:40:07 +08:00
Carter Li eee8fb78d2 Shell (FreeBSD): detect arg0 instead of exe path 2024-01-19 14:40:07 +08:00
Carter Li 413f91260d Processes (FreeBSD): don't count sub-threads as processes 2024-01-19 14:40:07 +08:00
李通洲 a44daa04d6 Shell (Windows): better support xonsh detection 2024-01-18 18:08:08 +08:00
李通洲 d6cb405afe Release: v2.6.1 2024-01-18 15:31:36 +08:00
李通洲 b2a853cb6e Doc: update changelog 2024-01-18 15:28:49 +08:00
李通洲 0168f2e9a8 Shell: improve xonsh version detection 2024-01-18 15:27:31 +08:00
李通洲 3992d85eb6 CPU (Linux): show vendor if no model name available 2024-01-18 15:16:46 +08:00
李通洲 5096180e92 CPU (Linux): don't access out-of-bound memory 2024-01-18 15:06:47 +08:00
李通洲 947d2ff0a9 Processing (Linux): return error when command is not found 2024-01-18 14:54:14 +08:00
李通洲 1e4f174415 Shell (macOS): improve handling of xonsh 2024-01-18 14:07:29 +08:00
李通洲 2808b1a653 TerminalShell: improve xonsh version detection 2024-01-17 23:45:39 +08:00
李通洲 c749f214e0 Global: silence warnings when building in 32bit environments 2024-01-17 23:12:55 +08:00
138 changed files with 3793 additions and 1126 deletions
+5 -4
View File
@@ -19,7 +19,10 @@ assignees: ''
# Often helpful information:
The content of the configuration file you use (if any)
Screenshot:
<!-- Paste the screenshot here -->
The content of the configuration file you use (if any):
```
//paste here
```
@@ -43,9 +46,7 @@ Output of `fastfetch --list-features`:
Paste the stacktrace here. You may get it with:
```
$ gdb /path/to/fastfetch
$ run
$ bt
$ gdb -q -ex 'set confirm off' -ex run -ex 'bt full' -ex quit --args /path/to/fastfetch
```
If you are able to identify which module crashed, the strace can be helpful too
+159 -57
View File
@@ -10,7 +10,7 @@ jobs:
steps:
- name: checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install codespell
shell: bash
@@ -26,7 +26,6 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
compiler: [
{ cc: gcc, cxx: "g++" },
{ cc: clang, cxx: "clang++" },
@@ -37,7 +36,7 @@ jobs:
# The feature libraries are all build against glibc, so they can't be used with musl
- compiler: { cc: "musl-gcc", cxx: "musl-g++" }
enableFeatures: ON
runs-on: ${{ matrix.os }}
runs-on: ubuntu-22.04
steps:
- name: checkout repository
uses: actions/checkout@v4
@@ -46,16 +45,16 @@ jobs:
run: uname -a
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y musl-dev musl-tools linux-headers-generic libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev directx-headers-dev libdrm-dev
run: sudo apt-get update && sudo apt-get install -y musl-dev musl-tools linux-headers-generic libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libddcutil-dev libchafa-dev libdrm-dev directx-headers-dev
- name: configure project
env:
CC: ${{ matrix.compiler.cc }}
CXX: ${{ matrix.compiler.cxx }}
run: cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_LIBPCI=${{ matrix.enableFeatures }} -DENABLE_VULKAN=${{ matrix.enableFeatures }} -DENABLE_WAYLAND=${{ matrix.enableFeatures }} -DENABLE_XCB_RANDR=${{ matrix.enableFeatures }} -DENABLE_XCB=${{ matrix.enableFeatures }} -DENABLE_XRANDR=${{ matrix.enableFeatures }} -DENABLE_X11=${{ matrix.enableFeatures }} -DENABLE_GIO=${{ matrix.enableFeatures }} -DENABLE_DCONF=${{ matrix.enableFeatures }} -DENABLE_DBUS=${{ matrix.enableFeatures }} -DENABLE_XFCONF=${{ matrix.enableFeatures }} -DENABLE_SQLITE3=${{ matrix.enableFeatures }} -DENABLE_RPM=${{ matrix.enableFeatures }} -DENABLE_IMAGEMAGICK7=${{ matrix.enableFeatures }} -DENABLE_IMAGEMAGICK6=${{ matrix.enableFeatures }} -DENABLE_CHAFA=${{ matrix.enableFeatures }} -DENABLE_ZLIB=${{ matrix.enableFeatures }} -DENABLE_EGL=${{ matrix.enableFeatures }} -DENABLE_GLX=${{ matrix.enableFeatures }} -DENABLE_OSMESA=${{ matrix.enableFeatures }} -DENABLE_OPENCL=${{ matrix.enableFeatures }} -DENABLE_LIBNM=${{ matrix.enableFeatures }} -DENABLE_PULSE=${{ matrix.enableFeatures }} -DENABLE_DIRECTX_HEADERS=${{ matrix.enableFeatures }} -DENABLE_DRM=${{ matrix.enableFeatures }} .
run: cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_VULKAN=${{ matrix.enableFeatures }} -DENABLE_WAYLAND=${{ matrix.enableFeatures }} -DENABLE_XCB_RANDR=${{ matrix.enableFeatures }} -DENABLE_XCB=${{ matrix.enableFeatures }} -DENABLE_XRANDR=${{ matrix.enableFeatures }} -DENABLE_X11=${{ matrix.enableFeatures }} -DENABLE_GIO=${{ matrix.enableFeatures }} -DENABLE_DCONF=${{ matrix.enableFeatures }} -DENABLE_DBUS=${{ matrix.enableFeatures }} -DENABLE_XFCONF=${{ matrix.enableFeatures }} -DENABLE_SQLITE3=${{ matrix.enableFeatures }} -DENABLE_RPM=${{ matrix.enableFeatures }} -DENABLE_IMAGEMAGICK7=${{ matrix.enableFeatures }} -DENABLE_IMAGEMAGICK6=${{ matrix.enableFeatures }} -DENABLE_CHAFA=${{ matrix.enableFeatures }} -DENABLE_ZLIB=${{ matrix.enableFeatures }} -DENABLE_EGL=${{ matrix.enableFeatures }} -DENABLE_GLX=${{ matrix.enableFeatures }} -DENABLE_OSMESA=${{ matrix.enableFeatures }} -DENABLE_OPENCL=${{ matrix.enableFeatures }} -DENABLE_LIBNM=${{ matrix.enableFeatures }} -DENABLE_PULSE=${{ matrix.enableFeatures }} -DENABLE_DIRECTX_HEADERS=${{ matrix.enableFeatures }} -DENABLE_DRM=${{ matrix.enableFeatures }} -DENABLE_DDCUTIL=${{ matrix.enableFeatures }} -DENABLE_CHAFA=${{ matrix.enableFeatures }} .
- name: build project
run: cmake --build .
run: cmake --build . --verbose -j4
- name: run tests
run: ctest
@@ -72,9 +71,68 @@ jobs:
- name: run flashfetch
run: time ./flashfetch
linux:
name: Linux
runs-on: ubuntu-20.04 # 22.04 ships a newer version of glibc than debian stable, allow those people to use the debian package
Linux-old-amd64:
name: Linux-old-amd64
runs-on: ubuntu-20.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: uname -a
run: uname -a
- name: install required packages
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libdrm-dev directx-headers-dev
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa ddcutil --ignore-dependencies
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: c
- name: configure project
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose -j4
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v3
- name: list features
run: ./fastfetch --list-features
- name: run fastfetch
run: time ./fastfetch -c presets/ci.jsonc
- name: run fastfetch --format json
run: time ./fastfetch -c presets/ci.jsonc --format json
- name: run flashfetch
run: time ./flashfetch
- name: print dependencies
run: ldd fastfetch
- name: run tests
run: ctest
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-old-amd64
path: ./fastfetch-*.*
linux-amd64:
name: Linux-amd64
runs-on: ubuntu-22.04 # Ubuntu 22.04 uses Glibc 2.35. Should be fine with Debian 12, which uses Glibc 2.36 (https://packages.debian.org/source/bookworm/glibc)
permissions:
security-events: write
contents: read
@@ -88,15 +146,15 @@ jobs:
run: uname -a
- 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 libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libdrm-dev directx-headers-dev
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libdrm-dev libddcutil-dev libchafa-dev directx-headers-dev
- name: install linuxbrew packages
run: |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick ddcutil --ignore-dependencies
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick --ignore-dependencies
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: c
@@ -104,10 +162,10 @@ jobs:
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
- name: build project
run: cmake --build . --target package --verbose
run: cmake --build . --target package --verbose -j4
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
- name: list features
run: ./fastfetch --list-features
@@ -134,11 +192,46 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux
name: fastfetch-linux-amd64
path: ./fastfetch-*.*
macos:
name: MacOS
linux-aarch64:
name: Linux-aarch64
runs-on: ubuntu-22.04
permissions:
security-events: write
contents: read
steps:
- name: checkout repository
uses: actions/checkout@v4
- name: run VM
uses: uraimo/run-on-arch-action@v2
id: runcmd
with:
arch: aarch64
distro: ubuntu22.04
githubToken: ${{ github.token }}
run: |
uname -a
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libnm-dev libpulse-dev libdrm-dev libddcutil-dev libchafa-dev directx-headers-dev rpm
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch -c presets/ci.jsonc
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-linux-aarch64
path: ./fastfetch-*.*
macos-universal:
name: macOS-universal
runs-on: macos-latest
permissions:
security-events: write
@@ -156,7 +249,7 @@ jobs:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install vulkan-loader vulkan-headers molten-vk imagemagick chafa
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: c
@@ -164,10 +257,10 @@ jobs:
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' .
- name: build project
run: cmake --build . --target package --verbose
run: cmake --build . --target package --verbose -j4
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
- name: list features
run: ./fastfetch --list-features
@@ -190,11 +283,11 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-macos
name: fastfetch-macos-universal
path: ./fastfetch-*.*
freebsd:
name: FreeBSD
freebsd-amd64:
name: FreeBSD-amd64
runs-on: macos-12
permissions:
security-events: write
@@ -211,9 +304,9 @@ jobs:
run: |
uname -a
sudo pkg update
sudo pkg install -y cmake git pkgconf binutils pciutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf ImageMagick6 ImageMagick7 chafa egl libosmesa opencl ocl-icd pulseaudio
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf ImageMagick6 ImageMagick7 chafa egl libosmesa opencl ocl-icd v4l_compat
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
cmake --build . --target package --verbose
cmake --build . --target package --verbose -j4
./fastfetch --list-features
time ./fastfetch
time ./fastfetch --format json
@@ -224,11 +317,11 @@ jobs:
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-freebsd
name: fastfetch-freebsd-amd64
path: ./fastfetch-*.*
win64:
name: Win64
windows-amd64:
name: Windows-amd64
runs-on: windows-latest
permissions:
security-events: write
@@ -254,7 +347,7 @@ jobs:
run: env PKG_CONFIG_PATH=/clang64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --verbose
run: cmake --build . --verbose -j4
- name: copy necessary dlls
run: cp /clang64/bin/{OpenCL,vulkan-1}.dll .
@@ -278,19 +371,19 @@ jobs:
run: ctest
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-$(./fastfetch --version-raw)-Win64.zip *.dll fastfetch.exe flashfetch.exe presets
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-amd64.zip *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-$(./fastfetch --version-raw)-Win64.7z *.dll fastfetch.exe flashfetch.exe presets
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-amd64.7z *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-win64
path: ./fastfetch-*-Win64.*
name: fastfetch-windows-amd64
path: ./fastfetch-windows-amd64.*
win32:
name: Win32
windows-i686:
name: Windows-i686
runs-on: windows-latest
permissions:
security-events: write
@@ -313,7 +406,7 @@ jobs:
run: uname -a
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: c, cpp
@@ -321,10 +414,10 @@ jobs:
run: env PKG_CONFIG_PATH=/clang32/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
- name: build project
run: cmake --build . --verbose
run: cmake --build . --verbose -j4
- name: perform CodeQL analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
- name: copy necessary dlls
run: cp /clang32/bin/{OpenCL,vulkan-1}.dll .
@@ -345,27 +438,28 @@ jobs:
run: ctest
- name: create zip archive
run: 7z a -tzip -mx9 -bd -y fastfetch-$(./fastfetch --version-raw)-Win32.zip *.dll fastfetch.exe flashfetch.exe presets
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-i686.zip *.dll fastfetch.exe flashfetch.exe presets
- name: create 7z archive
run: 7z a -t7z -mx9 -bd -y fastfetch-$(./fastfetch --version-raw)-Win32.7z *.dll fastfetch.exe flashfetch.exe presets
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-i686.7z *.dll fastfetch.exe flashfetch.exe presets
- name: upload artifacts
uses: actions/upload-artifact@v4
with:
name: fastfetch-win32
path: ./fastfetch-*-Win32.*
name: fastfetch-windows-i686
path: ./fastfetch-windows-i686.*
release:
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
name: Release
runs-on: ubuntu-latest
needs:
- linux
- macos
- freebsd
- win64
- win32
- linux-amd64
- linux-aarch64
- macos-universal
- freebsd-amd64
- windows-amd64
- windows-i686
permissions:
contents: write
steps:
@@ -376,38 +470,46 @@ jobs:
repository: ${{ github.repository }}
- name: download artifacts
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
uses: actions/download-artifact@v4
- name: rm old artifacts
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
run: |
rm -rf fastfetch-*-old-*
- name: create release
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.linux.outputs.ffversion }}
tag: ${{ needs.linux-amd64.outputs.ffversion }}
commit: ${{ github.sha }}
artifactErrorsFailBuild: true
artifacts: fastfetch-*/fastfetch-*
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux.outputs.ffversion }}/CHANGELOG.md) for details."
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details."
- name: download source tarballs
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
run: |
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-amd64.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
ls fastfetch-*/*
- name: generate release notes
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
run: |
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
echo -e "\n---\n\n<details><summary>SHA256SUMs</summary><br>\n\n\`\`\`" >> fastfetch-release-notes.md
sha256sum fastfetch-*/* >> fastfetch-release-notes.md
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
echo -e "\n<details><summary>SHA512SUMs</summary><br>\n\n\`\`\`" >> fastfetch-release-notes.md
sha512sum fastfetch-*/* >> fastfetch-release-notes.md
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
- name: update release body
if: needs.linux.outputs.ffversion != steps.get_version_release.outputs.release
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
uses: ncipollo/release-action@v1
with:
tag: ${{ needs.linux.outputs.ffversion }}
tag: ${{ needs.linux-amd64.outputs.ffversion }}
commit: ${{ github.sha }}
bodyFile: fastfetch-release-notes.md
allowUpdates: true
+94
View File
@@ -1,3 +1,97 @@
# 2.8.4
Bugfixes:
* Fix segfault if we fail to find `Vendor ID` in `lscpu` (#718, CPU, Linux)
* Fix multi-device bcachefs filesystem compatibility (#731, Disk, Linux)
Features:
* Support portable Windows Terminal settings (#720, Terminal, Windows)
* Support `--color-block-width` and `--color-block-range` (#721, Colors)
* Support `--diskio-detect-total` to show total bytes read/written (DiskIO)
* Support `--netio-detect-total` to show total bytes received/sent (NetIO)
* Support `--packages-disabled` to disable specified package manager (#729, Packages)
* Support `--display-order` to sort multiple displays in a specific order (Display)
* Support `--display-compact-type original-with-refresh-rate` to show refresh rates in compact (oneline) mode (Display)
# 2.8.3
Bugfixes:
* Fix GPU name detection for AMD graphic cards (GPU, Linux / FreeBSD)
# 2.8.2
Changes:
* The linux binaries are now built with glibc 2.35, which means they no longer support Debian 11 and Ubuntu 20.04. Users using these distros may download the artifacts `fastfetch-linux-old` from GitHub Actions.
Features:
* Rewrite GPU module, drop libpci dependency (GPU, Linux)
* Detect marketing name of Apple Silicon CPUs for asahi linux (CPU, Linux)
* Add new module `Camera`, which prints the name and resolution of connected cameras
Bugfixes:
* Fix compatibility with packages installed by flatpak (Terminal, Linux)
* Don't show an empty battery if no battery is detected (macOS, Battery)
* Don't show `not connected` if no power adapter is found (macOS / Linux, PowerAdapter)
* Make format of battery status be consistent with other platforms (Linux, Battery)
Logo:
* Print Asahi logo in asahi linux (Logo, Linux)
* Add Asahi2, z/OS, Tatra, PikaOS
# 2.7.1
Features:
* Config presets in app folder now work with symlinks
Bugfixes:
* Fix a possible segfault when detecting terminal (Terminal, Linux)
# 2.7.0
Features:
* Add new module `TerminalTheme`, which prints the foreground and background color of the current terminal window. Currently doesn't work on Windows.
* Allow command substitution when expanding paths. For example, now it's possible to use `"source": "$(ls ~/path/to/images/*.png | shuf -n 1)"` in JSONC config file to randomly choose an image to display. (#698)
* Use native methods instead of pciutils to detect GPUs in FreeBSD. (GPU, FreeBSD)
Bugfixes:
* Fix text formatting (Wifi, Linux)
* Fix terminal detection in some cases (Terminal)
* Remove trailing `\0` in JSON results (FreeBSD)
* Fix uninitialized variables (GPU, Linux)
* Fix a possible segfault (OpenCL)
Logo:
* Add ASCII logos for fedora immutable variants (#700)
# 2.6.3
Bugfixes:
* Fix module not working (Bluetooth)
# 2.6.2
Bugfixes:
* Fix building for GCC in Windows (Windows)
# 2.6.1
Features:
* Improve xonsh shell detection (Shell)
* Support colored percentage values (Bluetooth / Gamepad / Sound)
* Add `--<module>-percent-[green|yellow]` options to specify threshold of percentage colors
* eg. `--disk-percent-green 20 --disk-percent-yellow 50` will show green if disk usage is less than 20%, yellow if disk usage is less then 50%, and red otherwise.
* Add `--percent-color-[green|yellow|red]` options to specify color of different percent value states.
* eg. `--percent-color-green blue` will show blue color if percent value falls in green state.
* Improve Intel macbook support (macOS)
Bugfixes:
* Fix segfault in CPU module when running in aarch64 machine without `lscpu` installed (CPU, Linux)
* Don't use `login` as terminal process (Terminal, Linux)
* Silence warnings when building in 32bit machines.
* Create sub folders when writing config file (#690)
* Improve user specific locale detection; fix locale detection in Windows 7 (Locale)
* Fix GPU type detection (GPU, macOS)
# 2.6.0
Changes:
+24 -10
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.6.0
VERSION 2.8.4
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -42,7 +42,6 @@ include(CheckIncludeFile)
include(CMakeDependentOption)
cmake_dependent_option(ENABLE_LIBPCI "Enable libpci" ON "LINUX OR BSD" OFF)
cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR BSD OR WIN32 OR ANDROID" OFF)
cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR BSD" OFF)
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR BSD" OFF)
@@ -70,7 +69,6 @@ cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
cmake_dependent_option(ENABLE_PCI_MEMORY "Enable detecting GPU memory size with libpci" OFF "LINUX OR BSD" OFF)
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
@@ -265,7 +263,7 @@ file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
#######################
set(LIBFASTFETCH_SRC
src/common/bar.c
src/common/percent.c
src/common/commandoption.c
src/common/font.c
src/common/format.c
@@ -293,6 +291,7 @@ set(LIBFASTFETCH_SRC
src/detection/os/os.c
src/detection/packages/packages.c
src/detection/publicip/publicip.c
src/detection/terminaltheme/terminaltheme.c
src/detection/terminalfont/terminalfont.c
src/detection/terminalshell/terminalshell.c
src/detection/version/version.c
@@ -309,6 +308,7 @@ set(LIBFASTFETCH_SRC
src/modules/board/board.c
src/modules/brightness/brightness.c
src/modules/break/break.c
src/modules/camera/camera.c
src/modules/chassis/chassis.c
src/modules/colors/colors.c
src/modules/cpu/cpu.c
@@ -348,6 +348,7 @@ set(LIBFASTFETCH_SRC
src/modules/swap/swap.c
src/modules/media/media.c
src/modules/terminal/terminal.c
src/modules/terminaltheme/terminaltheme.c
src/modules/terminalfont/terminalfont.c
src/modules/terminalsize/terminalsize.c
src/modules/theme/theme.c
@@ -400,6 +401,7 @@ if(LINUX)
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_linux.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_linux.c
src/detection/icons/icons_linux.c
@@ -432,6 +434,7 @@ if(LINUX)
src/detection/wm/wm_nosupport.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
src/util/platform/FFPlatform_unix.c
)
elseif(ANDROID)
@@ -485,6 +488,7 @@ elseif(ANDROID)
src/detection/wm/wm_nosupport.c
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_nosupport.c
src/detection/camera/camera_android.c
src/util/platform/FFPlatform_unix.c
)
elseif(BSD)
@@ -514,7 +518,8 @@ elseif(BSD)
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
src/detection/font/font_linux.c
src/detection/gpu/gpu_linux.c
src/detection/gpu/gpu_bsd.c
src/detection/gpu/gpu_pci.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_bsd.c
src/detection/lm/lm_linux.c
@@ -547,6 +552,7 @@ elseif(BSD)
src/detection/wm/wm_nosupport.c
src/detection/de/de_linux.c
src/detection/wmtheme/wmtheme_linux.c
src/detection/camera/camera_linux.c
src/util/platform/FFPlatform_unix.c
)
elseif(APPLE)
@@ -602,6 +608,7 @@ elseif(APPLE)
src/detection/wm/wm_apple.c
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_apple.m
src/detection/camera/camera_apple.m
src/util/apple/cf_helpers.c
src/util/apple/osascript.m
src/util/platform/FFPlatform_unix.c
@@ -657,6 +664,7 @@ elseif(WIN32)
src/detection/wm/wm_windows.cpp
src/detection/de/de_nosupport.c
src/detection/wmtheme/wmtheme_windows.c
src/detection/camera/camera_windows.cpp
src/util/windows/getline.c
src/util/windows/com.cpp
src/util/windows/registry.c
@@ -790,10 +798,6 @@ function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME)
endforeach()
endfunction()
ff_lib_enable(LIBPCI
"libpci"
"Pci"
)
ff_lib_enable(VULKAN
"vulkan"
"Vulkan"
@@ -916,9 +920,11 @@ if(LINUX)
)
elseif(APPLE)
target_link_libraries(libfastfetch
PRIVATE "-framework AVFoundation"
PRIVATE "-framework Cocoa"
PRIVATE "-framework CoreFoundation"
PRIVATE "-framework CoreAudio"
PRIVATE "-framework CoreMedia"
PRIVATE "-framework CoreVideo"
PRIVATE "-framework CoreWLAN"
PRIVATE "-framework IOBluetooth"
@@ -1103,6 +1109,14 @@ install(
##################
set(CPACK_GENERATOR "TGZ;ZIP")
if(APPLE)
string(TOLOWER "${CMAKE_PROJECT_NAME}-macos-universal" CPACK_PACKAGE_FILE_NAME)
else() # We don't use this in Windows
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
set(CMAKE_SYSTEM_PROCESSOR "amd64")
endif()
string(TOLOWER "${CMAKE_PROJECT_NAME}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}" CPACK_PACKAGE_FILE_NAME)
endif()
if(LINUX)
set(CPACK_GENERATOR "${CPACK_GENERATOR};DEB;RPM")
@@ -1119,7 +1133,7 @@ set(CPACK_SET_DESTDIR ON)
set(CPACK_PACKAGE_CONTACT "Linus Dierheimer <Linus@Dierheimer.de>")
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.\
It is written mostly in C to achieve much better performance.\
")
include(CPack)
+10 -2
View File
@@ -28,11 +28,13 @@ There are [screenshots on different platforms](https://github.com/fastfetch-cli/
### Linux
* Debian / Ubuntu: Download `fastfetch-<version>-Linux.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and `dpkg -i fastfetch-<version>-Linux.deb`
* Arch Linux: `sudo pacman -S fastfetch`
* Arch Linux: `sudo pacman -S fastfetch`. You can also find fastfetch [on the AUR](https://aur.archlinux.org/packages/fastfetch-git).
* Fedora: `sudo dnf install fastfetch`
* Gentoo: `sudo emerge --ask app-misc/fastfetch`
* NixOS: `sudo nix-shell -p fastfetch`
* Alpine: `apk add --upgrade fastfetch`
* NixOS: `nix-shell -p fastfetch`
* openSUSE: `sudo zypper install fastfetch`
* ALT Linux: `sudo apt-get install fastfetch`
Replace sudo with doas depending on what you use.
@@ -40,8 +42,14 @@ Replace sudo with doas depending on what you use.
### macOS
...via [HomeBrew](https://brew.sh):
`brew install fastfetch`
...via [MacPorts](https://www.macports.org):
`sudo port install fastfetch`
### Windows
`scoop install fastfetch`
+18
View File
@@ -0,0 +1,18 @@
fastfetch (2.7.1ubuntu2) jammy; urgency=medium
* Ignore .git
-- Carter Li <zhangsongcui@live.cn> Wed, 07 Feb 2024 14:23:23 +0800
fastfetch (2.7.1ubuntu1) jammy; urgency=medium
* Update build scripts
-- Carter Li <zhangsongcui@live.cn> Wed, 07 Feb 2024 13:53:37 +0800
fastfetch (2.7.1) jammy; urgency=medium
* Initial release.
-- Carter Li <zhangsongcui@live.cn> Tue, 06 Feb 2024 15:01:11 +0800
+1
View File
@@ -0,0 +1 @@
12
+13
View File
@@ -0,0 +1,13 @@
Source: fastfetch
Section: universe/utils
Priority: optional
Maintainer: Carter Li <zhangsongcui@live.cn>
Build-Depends: libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libxfconf-0-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, libosmesa6-dev, ocl-icd-opencl-dev, libnm-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
Standards-Version: 4.0.0
Homepage: https://github.com/fastfetch-cli/fastfetch
Package: fastfetch
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way.
It is written mainly in C, with performance and customizability in mind.
+11
View File
@@ -0,0 +1,11 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: fastfetch
Source: https://github.com/fastfetch-cli/fastfetch
Files: *
Copyright: 2024 fastfetch-cli
License: Expat
Files: src/3rdparty/yyjson/*
Copyright: 2020 YaoYuan
License: Expat
+1
View File
@@ -0,0 +1 @@
fastfetch_2.7.1ubuntu2_source.buildinfo universe/utils optional
Vendored Executable
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
debuild -S -i -I
dput ppa:zhangsongcui3371/fastfetch ~/fastfetch_*.changes
Vendored Executable
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/make -f
%:
dh $@ --buildsystem=cmake+ninja
override_dh_ctest_configure:
dh_ctest_configure -- -DSET_TWEAK=OFF -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
+4
View File
@@ -0,0 +1,4 @@
version=4
opts="filenamemangle=s%.*/@ANY_VERSION@%@PACKAGE@-$1.tar.gz%,searchmode=plain" \
https://api.github.com/repos/fastfetch-cli/fastfetch/releases?per_page=100 \
https://api.github.com/repos/fastfetch-cli/fastfetch/tarball/@ANY_VERSION@
+183 -17
View File
@@ -26,6 +26,24 @@
"format": {
"description": "Output format of the module",
"type": "string"
},
"percent": {
"description": "Threshold of percentage colors",
"type": "object",
"properties": {
"green": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"description": "Value less then green will be shown in green"
},
"yellow": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"description": "Value greater than green and less then yellow will be shown in yellow.\nValue greater than yellow will be shown in red"
}
}
}
},
"type": "object",
@@ -439,6 +457,24 @@
"minimum": 0,
"maximum": 9,
"default": 0
},
"color": {
"type": "object",
"description": "Set color used in different states of percentage bars and numbers",
"properties": {
"green": {
"description": "Color used in green state",
"$ref": "#/$defs/colors"
},
"yellow": {
"description": "Color used in yellow state",
"$ref": "#/$defs/colors"
},
"red": {
"description": "Color used in red state",
"$ref": "#/$defs/colors"
}
}
}
}
},
@@ -612,6 +648,7 @@
"terminal",
"terminalfont",
"terminalsize",
"terminaltheme",
"title",
"theme",
"uptime",
@@ -672,10 +709,6 @@
"const": "font",
"description": "Print system font name"
},
{
"const": "gamepad",
"description": "List connected gamepads"
},
{
"const": "host",
"description": "Print product name of your computer"
@@ -700,10 +733,6 @@
"const": "media",
"description": "Print playing song name"
},
{
"const": "memory",
"description": "Print system memory usage info"
},
{
"const": "monitor",
"description": "Print connected physical monitor information"
@@ -732,10 +761,6 @@
"const": "shell",
"description": "Print current shell name and version"
},
{
"const": "swap",
"description": "Print swap (paging file) space usage"
},
{
"const": "terminal",
"description": "Print current terminal name and version"
@@ -748,6 +773,10 @@
"const": "terminalsize",
"description": "Print current terminal size"
},
{
"const": "terminaltheme",
"description": "Print current terminal theme (foreground and background colors)"
},
{
"const": "theme",
"description": "Print current theme of desktop environment"
@@ -814,6 +843,9 @@
"type": "boolean",
"default": false
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
@@ -841,6 +873,9 @@
"type": "boolean",
"default": false
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
@@ -863,6 +898,9 @@
"const": "brightness",
"description": "Print current brightness level of your monitors"
},
"percent": {
"$ref": "#/$defs/percent"
},
"ddcciSleep": {
"type": "integer",
"description": "Set the sleep times (in ms) when sending DDC/CI requests.\nSee <https://www.ddcutil.com/performance_options/#option-sleep-multiplier> for detail",
@@ -934,6 +972,9 @@
"const": "cpuusage",
"description": "Print CPU usage. Costs some time to collect data"
},
"percent": {
"$ref": "#/$defs/percent"
},
"separate": {
"type": "boolean",
"description": "Display CPU usage per CPU logical core, instead of an average result",
@@ -966,6 +1007,29 @@
"type": "integer",
"minimum": 0,
"default": 0
},
"block": {
"description": "Set behavior of block printing",
"type": "object",
"properties": {
"width": {
"description": "Set the block width in spaces",
"type": "integer",
"minimum": 1,
"default": 3
},
"range": {
"description": "Set the range of colors in the blocks to print",
"type": "array",
"items": {
"type": "integer",
"minimum": 0,
"maximum": 15
},
"minItems": 2,
"maxItems": 2
}
}
}
}
},
@@ -1037,7 +1101,9 @@
"enum": [
"none",
"original",
"scaled"
"scaled",
"original-with-refresh-rate",
"scaled-with-refresh-rate"
],
"description": "Set if all displays should be printed in one line",
"default": "none"
@@ -1047,6 +1113,15 @@
"type": "boolean",
"default": false
},
"order": {
"description": "Set the order should be used when printing",
"enum": [
"none",
"asc",
"desc"
],
"default": "none"
},
"key": {
"$ref": "#/$defs/key"
},
@@ -1103,6 +1178,9 @@
"description": "Use f_bavail (lpFreeBytesAvailableToCaller for Windows) instead of f_bfree to calculate used bytes",
"default": false
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
@@ -1129,6 +1207,11 @@
"description": "Show disks with given name prefix only",
"type": "string"
},
"detectTotal": {
"description": "Detect total bytes instead of current rate",
"type": "boolean",
"default": false
},
"key": {
"$ref": "#/$defs/key"
},
@@ -1170,6 +1253,31 @@
}
}
},
{
"title": "Gamepad",
"properties": {
"type": {
"const": "gamepad",
"description": "List connected gamepads"
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
"keyColor": {
"$ref": "#/$defs/keyColor"
},
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"format": {
"$ref": "#/$defs/format"
}
},
"additionalProperties": false
},
{
"title": "GPU",
"properties": {
@@ -1272,6 +1380,31 @@
},
"additionalProperties": false
},
{
"title": "Memory",
"properties": {
"type": {
"const": "memory",
"description": "Print system memory usage info"
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
"keyColor": {
"$ref": "#/$defs/keyColor"
},
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"format": {
"$ref": "#/$defs/format"
}
},
"additionalProperties": false
},
{
"title": "NetIO",
"properties": {
@@ -1288,6 +1421,11 @@
"type": "boolean",
"default": true
},
"detectTotal": {
"description": "Detect total bytes instead of current rate",
"type": "boolean",
"default": false
},
"key": {
"$ref": "#/$defs/key"
},
@@ -1342,10 +1480,10 @@
"const": "packages",
"description": "List installed package managers and count of installed packages"
},
"winget": {
"description": "Set if winget package count should be detected.\nNote this is very slow operation. Please make sure `winget list` works before enable this option\nWindows only",
"type": "boolean",
"default": false
"disabled": {
"description": "A colon separated list of package managers to be disabled when detecting",
"type": "string",
"default": "winget"
},
"key": {
"$ref": "#/$defs/key"
@@ -1458,6 +1596,34 @@
],
"default": "main"
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
"keyColor": {
"$ref": "#/$defs/keyColor"
},
"keyWidth": {
"$ref": "#/$defs/keyWidth"
},
"format": {
"$ref": "#/$defs/format"
}
},
"additionalProperties": false
},
{
"title": "Swap",
"properties": {
"type": {
"const": "swap",
"description": "Print swap (paging file) space usage"
},
"percent": {
"$ref": "#/$defs/percent"
},
"key": {
"$ref": "#/$defs/key"
},
+2
View File
@@ -28,6 +28,7 @@
"terminal",
"terminalfont",
"terminalsize",
"terminaltheme",
"cpu",
"cpuusage",
"gpu",
@@ -49,6 +50,7 @@
"users",
"bluetooth",
"sound",
"camera",
"gamepad",
"weather",
"netio",
+2
View File
@@ -34,6 +34,7 @@
"terminal",
"terminalfont",
"terminalsize",
"terminaltheme",
"cpu",
"cpuusage",
"gpu",
@@ -55,6 +56,7 @@
"users",
"bluetooth",
"sound",
"camera",
"gamepad",
{
"type": "weather",
-111
View File
@@ -1,111 +0,0 @@
#include "common/bar.h"
#include "common/color.h"
#include "util/textModifier.h"
void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, uint8_t red)
{
assert(green <= 100 && yellow <= 100 && red <= 100);
const FFOptionsDisplay* options = &instance.config.display;
uint32_t blocksPercent = (uint32_t) (percent / 100.0 * options->barWidth + 0.5);
uint32_t blocksGreen = (uint32_t) (green / 100.0 * options->barWidth + 0.5);
uint32_t blocksYellow = (uint32_t) (yellow / 100.0 * options->barWidth + 0.5);
uint32_t blocksRed = (uint32_t) (red / 100.0 * options->barWidth + 0.5);
assert(blocksPercent <= options->barWidth);
if(options->barBorder)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m[ ");
else
ffStrbufAppendS(buffer, "[ ");
}
for (uint32_t i = 0; i < blocksPercent; ++i)
{
if(!options->pipe)
{
if (i == blocksGreen)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m");
else if (i == blocksYellow)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m");
else if (i == blocksRed)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m");
}
ffStrbufAppend(buffer, &options->barCharElapsed);
}
if (blocksPercent < options->barWidth)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
for (uint32_t i = blocksPercent; i < options->barWidth; ++i)
ffStrbufAppend(buffer, &options->barCharTotal);
}
if(options->barBorder)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m ]");
else
ffStrbufAppendS(buffer, " ]");
}
if(!options->pipe)
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
}
// if (green < yellow)
// [0, green]: print green
// (green, yellow]: print yellow
// (yellow, 100]: print red
//
// if (green > yellow)
// [green, 100]: print green
// [yellow, green): print yellow
// [0, yellow): PRINT RED
void ffAppendPercentNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses)
{
assert(green <= 100 && yellow <= 100);
const FFOptionsDisplay* options = &instance.config.display;
bool colored = !!(options->percentType & FF_PERCENTAGE_TYPE_NUM_COLOR_BIT);
if (parentheses)
ffStrbufAppendC(buffer, '(');
if (colored && !options->pipe)
{
if(percent != percent)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
else if(green < yellow)
{
if (percent <= green)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m");
else if (percent <= yellow)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m");
else
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m");
}
else
{
if (percent >= green)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_GREEN "m");
else if (percent >= yellow)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_YELLOW "m");
else
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_RED "m");
}
}
ffStrbufAppendF(buffer, "%.*f%%", options->percentNdigits, percent);
if (colored && !options->pipe)
{
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
}
if (parentheses)
ffStrbufAppendC(buffer, ')');
}
-14
View File
@@ -1,14 +0,0 @@
#pragma once
#include "fastfetch.h"
enum
{
FF_PERCENTAGE_TYPE_NUM_BIT = 1 << 0,
FF_PERCENTAGE_TYPE_BAR_BIT = 1 << 1,
FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT = 1 << 2,
FF_PERCENTAGE_TYPE_NUM_COLOR_BIT = 1 << 3,
};
void ffAppendPercentBar(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, uint8_t red);
void ffAppendPercentNum(FFstrbuf* buffer, double percent, uint8_t green, uint8_t yellow, bool parentheses);
+1 -1
View File
@@ -57,7 +57,7 @@ static inline uint32_t getArgumentIndex(const FFstrbuf* placeholderValue)
uint32_t result = UINT32_MAX;
if(placeholderValue->chars[0] != '-')
sscanf(placeholderValue->chars, "%u", &result);
sscanf(placeholderValue->chars, "%" PRIu32, &result);
return result == 0 ? UINT32_MAX : result;
}
+3 -3
View File
@@ -163,9 +163,6 @@ void ffListFeatures(void)
#ifdef FF_HAVE_THREADS
"threads\n"
#endif
#ifdef FF_HAVE_LIBPCI
"libpci\n"
#endif
#ifdef FF_HAVE_VULKAN
"vulkan\n"
#endif
@@ -241,6 +238,9 @@ void ffListFeatures(void)
#ifdef FF_HAVE_DDCUTIL
"libddcutil\n"
#endif
#if __has_include(<linux/videodev2.h>)
"videodev2\n"
#endif
#ifdef FF_HAVE_DIRECTX_HEADERS
"Directx Headers\n"
#endif
+1 -1
View File
@@ -115,7 +115,7 @@ bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* o
#if __has_include(<wordexp.h>) // https://github.com/termux/termux-packages/pull/7056
wordexp_t exp;
if(wordexp(in, &exp, WRDE_NOCMD) != 0)
if(wordexp(in, &exp, 0) != 0)
return false;
if (exp.we_wordc == 1)
+2
View File
@@ -15,6 +15,7 @@ static FFModuleBaseInfo* B[] = {
};
static FFModuleBaseInfo* C[] = {
(void*) &instance.config.modules.camera,
(void*) &instance.config.modules.chassis,
(void*) &instance.config.modules.command,
(void*) &instance.config.modules.colors,
@@ -124,6 +125,7 @@ static FFModuleBaseInfo* T[] = {
(void*) &instance.config.modules.terminal,
(void*) &instance.config.modules.terminalFont,
(void*) &instance.config.modules.terminalSize,
(void*) &instance.config.modules.terminalTheme,
(void*) &instance.config.modules.title,
(void*) &instance.config.modules.theme,
NULL,
+1 -1
View File
@@ -143,7 +143,7 @@ void ffOptionParseColor(const char* value, FFstrbuf* buffer)
while(*value != '\0')
{
#define FF_APPEND_COLOR_CODE_COND(prefix, code) \
if(strncasecmp(value, #prefix, strlen(#prefix)) == 0) { ffStrbufAppendS(buffer, code); value += strlen(#prefix); }
if(ffStrStartsWithIgnCase(value, #prefix)) { ffStrbufAppendS(buffer, code); value += strlen(#prefix); }
FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET)
else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD)
+211
View File
@@ -0,0 +1,211 @@
#include "fastfetch.h"
#include "common/percent.h"
#include "common/color.h"
#include "common/option.h"
#include "common/jsonconfig.h"
#include "util/textModifier.h"
#include "util/stringUtils.h"
void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentConfig config)
{
uint8_t green = config.green, yellow = config.yellow;
assert(green <= 100 && yellow <= 100);
const FFOptionsDisplay* options = &instance.config.display;
uint32_t blocksPercent = (uint32_t) (percent / 100.0 * options->barWidth + 0.5);
assert(blocksPercent <= options->barWidth);
if(options->barBorder)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m[ ");
else
ffStrbufAppendS(buffer, "[ ");
}
if (percent != percent)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
for (uint32_t i = 0; i < options->barWidth; ++i)
ffStrbufAppend(buffer, &options->barCharElapsed);
}
else
{
const char* colorGreen = instance.config.display.percentColorGreen.chars;
const char* colorYellow = instance.config.display.percentColorYellow.chars;
const char* colorRed = instance.config.display.percentColorRed.chars;
for (uint32_t i = 0; i < blocksPercent; ++i)
{
if(!options->pipe)
{
uint32_t section1Begin = (uint32_t) ((green <= yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
uint32_t section2Begin = (uint32_t) ((green > yellow ? green : yellow) / 100.0 * options->barWidth + 0.5);
if (i == section2Begin)
ffStrbufAppendF(buffer, "\e[%sm", (green > yellow ? colorGreen : colorRed));
else if (i == section1Begin)
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
else if (i == 0)
ffStrbufAppendF(buffer, "\e[%sm", (green <= yellow ? colorGreen : colorRed));
}
ffStrbufAppend(buffer, &options->barCharElapsed);
}
if (blocksPercent < options->barWidth)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m");
for (uint32_t i = blocksPercent; i < options->barWidth; ++i)
ffStrbufAppend(buffer, &options->barCharTotal);
}
}
if(options->barBorder)
{
if(!options->pipe)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_WHITE "m ]");
else
ffStrbufAppendS(buffer, " ]");
}
if(!options->pipe)
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
}
void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentConfig config, bool parentheses)
{
uint8_t green = config.green, yellow = config.yellow;
assert(green <= 100 && yellow <= 100);
const FFOptionsDisplay* options = &instance.config.display;
bool colored = !!(options->percentType & FF_PERCENTAGE_TYPE_NUM_COLOR_BIT);
if (parentheses)
ffStrbufAppendC(buffer, '(');
if (colored && !options->pipe)
{
const char* colorGreen = instance.config.display.percentColorGreen.chars;
const char* colorYellow = instance.config.display.percentColorYellow.chars;
const char* colorRed = instance.config.display.percentColorRed.chars;
if(percent != percent)
ffStrbufAppendS(buffer, "\e[" FF_COLOR_FG_LIGHT_BLACK "m");
else if(green <= yellow)
{
if (percent > yellow)
ffStrbufAppendF(buffer, "\e[%sm", colorRed);
else if (percent > green)
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
else
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
}
else
{
if (percent < yellow)
ffStrbufAppendF(buffer, "\e[%sm", colorRed);
else if (percent < green)
ffStrbufAppendF(buffer, "\e[%sm", colorYellow);
else
ffStrbufAppendF(buffer, "\e[%sm", colorGreen);
}
}
ffStrbufAppendF(buffer, "%.*f%%", options->percentNdigits, percent);
if (colored && !options->pipe)
{
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
}
if (parentheses)
ffStrbufAppendC(buffer, ')');
}
bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentConfig* config)
{
if (!ffStrStartsWithIgnCase(subkey, "percent-"))
return false;
subkey += strlen("percent-");
if (ffStrEqualsIgnCase(subkey, "green"))
{
uint32_t num = ffOptionParseUInt32(key, value);
if (num > 100)
{
fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key);
exit(480);
}
config->green = (uint8_t) num;
return true;
}
if (ffStrEqualsIgnCase(subkey, "yellow"))
{
uint32_t num = ffOptionParseUInt32(key, value);
if (num > 100)
{
fprintf(stderr, "Error: usage: %s must be between 0 and 100\n", key);
exit(480);
}
config->yellow = (uint8_t) num;
return true;
}
return false;
}
bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentConfig* config)
{
if (!ffStrEqualsIgnCase(key, "percent"))
return false;
if (!yyjson_is_obj(value))
{
fprintf(stderr, "Error: usage: %s must be an object\n", key);
exit(480);
}
yyjson_val* greenVal = yyjson_obj_get(value, "green");
if (greenVal)
{
int num = yyjson_get_int(greenVal);
if (num < 0 || num > 100)
{
fputs("Error: usage: percent.green must be between 0 and 100\n", stderr);
exit(480);
}
config->green = (uint8_t) num;
}
yyjson_val* yellowVal = yyjson_obj_get(value, "yellow");
if (yellowVal)
{
int num = yyjson_get_int(yellowVal);
if (num < 0 || num > 100)
{
fputs("Error: usage: percent.yellow must be between 0 and 100\n", stderr);
exit(480);
}
config->yellow = (uint8_t) num;
}
return true;
}
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentConfig defaultConfig, FFPercentConfig config)
{
if (config.green == defaultConfig.green && config.yellow == defaultConfig.yellow)
return;
yyjson_mut_val* percent = yyjson_mut_obj_add_obj(doc, module, "percent");
if (config.green != defaultConfig.green)
yyjson_mut_obj_add_uint(doc, percent, "green", config.green);
if (config.yellow != defaultConfig.yellow)
yyjson_mut_obj_add_uint(doc, percent, "yellow", config.yellow);
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "util/FFstrbuf.h"
enum
{
FF_PERCENTAGE_TYPE_NUM_BIT = 1 << 0,
FF_PERCENTAGE_TYPE_BAR_BIT = 1 << 1,
FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT = 1 << 2,
FF_PERCENTAGE_TYPE_NUM_COLOR_BIT = 1 << 3,
};
typedef struct FFPercentConfig
{
uint8_t green;
uint8_t yellow;
} FFPercentConfig;
// if (green <= yellow)
// [0, green]: print green
// (green, yellow]: print yellow
// (yellow, 100]: print red
//
// if (green > yellow)
// [green, 100]: print green
// [yellow, green): print yellow
// [0, yellow): print red
void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentConfig config);
void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentConfig config, bool parentheses);
typedef struct yyjson_val yyjson_val;
typedef struct yyjson_mut_doc yyjson_mut_doc;
typedef struct yyjson_mut_val yyjson_mut_val;
bool ffPercentParseCommandOptions(const char* key, const char* subkey, const char* value, FFPercentConfig* config);
bool ffPercentParseJsonObject(const char* key, yyjson_val* value, FFPercentConfig* config);
void ffPercentGenerateJsonConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFPercentConfig defaultConfig, FFPercentConfig config);
+16 -9
View File
@@ -13,13 +13,6 @@
enum { FF_PIPE_BUFSIZ = 8192 };
static inline void waitpid_wrapper(const pid_t* pid)
{
// remove zombie processes
if (*pid > 0)
waitpid(*pid, NULL, 0);
}
static inline int ffPipe2(int *fds, int flags)
{
#ifdef __APPLE__
@@ -41,7 +34,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if(ffPipe2(pipes, O_CLOEXEC) == -1)
return "pipe() failed";
__attribute__((__cleanup__(waitpid_wrapper))) pid_t childPid = fork();
pid_t childPid = fork();
if(childPid == -1)
{
close(pipes[0]);
@@ -74,11 +67,13 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if (poll(&pollfd, 1, timeout) == 0)
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) timeout";
}
else if (pollfd.revents & POLLERR)
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) error";
}
}
@@ -87,7 +82,19 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if (nRead > 0)
ffStrbufAppendNS(buffer, (uint32_t) nRead, str);
else if (nRead == 0)
return NULL;
{
int stat_loc = 0;
if (waitpid(childPid, &stat_loc, 0) == childPid)
{
if (!WIFEXITED(stat_loc))
return "child process exited abnormally";
if (WEXITSTATUS(stat_loc) == 127)
return "command was not found";
// We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c`
return NULL;
}
return "waitpid() failed";
}
else if (nRead < 0)
break;
};
+1 -1
View File
@@ -42,6 +42,6 @@ static inline void ffTimeSleep(uint32_t msec)
#ifdef _WIN32
SleepEx(msec, TRUE);
#else
nanosleep(&(struct timespec){ msec / 1000, (msec % 1000) * 1000000 }, NULL);
nanosleep(&(struct timespec){ msec / 1000, (long) (msec % 1000) * 1000000 }, NULL);
#endif
}
+158 -12
View File
@@ -122,7 +122,10 @@
{
"long": "ds-force-drm",
"desc": "Set if only DRM should be used to detect displays",
"remark": "Use this option if you encountered problems with other detection method. Linux only",
"remark": [
"Use this option if you encountered problems with other detection method.",
"Linux only"
],
"arg": {
"type": "enum",
"optional": true,
@@ -198,6 +201,7 @@
{
"long": "logo-color-[1-9]",
"desc": "Overwrite a color in the logo",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color"
},
@@ -432,6 +436,7 @@
{
"long": "color-keys",
"desc": "Set the color of the keys",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color"
}
@@ -439,6 +444,7 @@
{
"long": "color-title",
"desc": "Set the color of the title",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color"
}
@@ -534,7 +540,13 @@
{
"long": "percent-type",
"desc": "Set the percentage output type",
"remark": "1 for percentage number, 2 for bar, 3 for both, 6 for bar only, 9 for colored number",
"remark": [
"1 for percentage number",
"2 for bar",
"3 for both",
"6 for bar only",
"9 for colored number"
],
"arg": {
"type": "num",
"default": 9
@@ -548,6 +560,33 @@
"default": 0
}
},
{
"long": "percent-color-green",
"desc": "Set color used in green state of percentage bars and numbers",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color",
"default": "green"
}
},
{
"long": "percent-color-yellow",
"desc": "Set color used in yellow state of percentage bars and numbers",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color",
"default": "light_yellow"
}
},
{
"long": "percent-color-red",
"desc": "Set color used in red state of percentage bars and numbers",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color",
"default": "light_red"
}
},
{
"long": "bar-char-elapsed",
"desc": "Set the character to use in elapsed part of percentage bars",
@@ -821,6 +860,7 @@
{
"long": "title-color-user",
"desc": "Set color of the user name (left part)",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color",
"default": "Use color of \"--color-title\""
@@ -829,6 +869,7 @@
{
"long": "title-color-at",
"desc": "Set color of the @ symbol (middle part)",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color",
"default": "Use color of \"--color-title\""
@@ -837,6 +878,7 @@
{
"long": "title-color-host",
"desc": "Set color of the host name (right part)",
"remark": "See `-h color` for the list of available colors",
"arg": {
"type": "color",
"default": "default"
@@ -930,6 +972,14 @@
"default": false
}
},
{
"long": "diskio-detect-total",
"desc": "Detect total bytes instead of current rate",
"arg": {
"type": "bool",
"default": false
}
},
{
"long": "diskio-name-prefix",
"desc": "Show disks with given name prefix only",
@@ -963,13 +1013,16 @@
}
},
{
"long": "packages-winget",
"desc": "Set if winget package count should be detected",
"remark": "This option is extremely slow. You may need to increase value of '--processing-timeout' to make it actually work",
"long": "packages-disabled",
"desc": "A colon separated list of package managers to be disabled when detecting",
"remark": [
"Some detection methods can be very slow.",
"You may need to increase value of '--processing-timeout' to make it actually work.",
"Use `--packages-disabled none` to enable all."
],
"arg": {
"type": "bool",
"optional": true,
"default": false
"type": "string",
"default": "winget"
}
},
{
@@ -980,7 +1033,9 @@
"enum": {
"none": "Disable this compact mode",
"original": "Print original resolutions",
"scaled": "Print scaled resolutions"
"scaled": "Print scaled resolutions",
"original-with-refresh-rate": "Print original resolutions with refresh rate",
"scaled-with-refresh-rate": "Print scaled resolutions with refresh rate"
},
"default": "none"
}
@@ -994,6 +1049,19 @@
"default": false
}
},
{
"long": "display-order",
"desc": "Set the order should be used when printing displays",
"arg": {
"type": "enum",
"enum": {
"none": "Use the detected order",
"asc": "Sort by display name ascendingly",
"desc": "Sort by display name descendingly"
},
"default": "none"
}
},
{
"long": "brightness-ddcci-sleep",
"desc": "Set the sleep times (in ms) when sending DDC/CI requests",
@@ -1019,7 +1087,10 @@
{
"long": "battery-use-setup-api",
"desc": "Set if \"SetupAPI\" should be used on Windows to detect battery info",
"remark": "SetupAPI supports multi batteries, but slower. Windows only",
"remark": [
"SetupAPI supports multi batteries, but slower.",
"Windows only"
],
"arg": {
"type": "bool",
"optional": true,
@@ -1055,7 +1126,10 @@
{
"long": "de-slow-version-detection",
"desc": "Set if DE version should be detected with slow operations",
"remark": "Usually is not necessary. Linux only",
"remark": [
"It's only used as a fallback method. Please file a bug report if you encounter any issues.",
"Linux only"
],
"arg": {
"type": "bool",
"optional": true,
@@ -1074,7 +1148,10 @@
{
"long": "gpu-driver-specific",
"desc": "Use driver specific method to detect more detailed GPU information (memory usage, core count, etc)",
"remark": "Correctly NVML (NVIDIA) and IGCL (Intel, Windows only) are supported. Both require the latest proprietary driver to be installed",
"remark": [
"Correctly NVML (NVIDIA) and IGCL (Intel, Windows only) are supported.",
"Both require the latest proprietary driver to be installed."
],
"arg": {
"type": "bool",
"optional": true,
@@ -1192,6 +1269,14 @@
"default": true
}
},
{
"long": "netio-detect-total",
"desc": "Detect total bytes instead of current rate",
"arg": {
"type": "bool",
"default": false
}
},
{
"long": "publicip-timeout",
"desc": "Time in milliseconds to wait for the public ip server to respond",
@@ -1309,6 +1394,44 @@
"type": "num",
"default": 0
}
},
{
"long": "colors-block-width",
"desc": "Set the block width in spaces",
"arg": {
"type": "num",
"default": 3
}
},
{
"long": "colors-block-range-start",
"desc": "Set the start range of colors in the blocks to print",
"remark": [
"Display colors 0-15 in the blocks. (16 colors)",
"Display colors 0-7 in the blocks. (8 colors)",
"Only works for `--colors-symbol block`.",
"Must be in range 0-15",
"See also `--colors-range-end`"
],
"arg": {
"type": "num",
"default": 0
}
},
{
"long": "colors-block-range-end",
"desc": "Set the end range of colors in the blocks to print",
"remark": [
"Display colors 0-15 in the blocks. (16 colors)",
"Display colors 0-7 in the blocks. (8 colors)",
"Only works for `--colors-symbol block`.",
"Must be in range 0-15",
"See also `--colors-range-start`"
],
"arg": {
"type": "num",
"default": 15
}
}
],
"General module": [
@@ -1351,6 +1474,29 @@
"type": "num"
},
"pseudo": true
},
{
"long": "<module>-percent-green",
"desc": [
"Threshold of percentage colors",
"Value less then percent-green will be shown in green"
],
"arg": {
"type": "num"
},
"pseudo": true
},
{
"long": "<module>-percent-yellow",
"desc": [
"Threshold of percentage colors",
"Value greater than percent-green and less then yellow will be shown in yellow",
"Value greater than percent-yellow will be shown in red"
],
"arg": {
"type": "num"
},
"pseudo": true
}
]
}
+31 -20
View File
@@ -20,6 +20,14 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
if (IORegistryEntryCreateCFProperties(entryBattery, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
continue;
int currentCapacity, maxCapacity;
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity) != NULL || maxCapacity <= 0)
continue;
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), &currentCapacity) != NULL || currentCapacity <= 0)
continue;
bool boolValue;
FFBatteryResult* battery = ffListAdd(results);
@@ -30,24 +38,16 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
ffStrbufInit(&battery->technology);
ffStrbufInit(&battery->status);
ffStrbufInit(&battery->manufactureDate);
battery->capacity = 0.0/0.0;
int currentCapacity, maxCapacity;
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity) != NULL || maxCapacity <= 0)
continue;
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), &currentCapacity) != NULL || currentCapacity <= 0)
continue;
battery->capacity = currentCapacity * 100.0 / maxCapacity;
ffCfDictGetString(properties, CFSTR(kIOPMDeviceNameKey), &battery->modelName);
ffCfDictGetString(properties, CFSTR(kIOPMPSSerialKey), &battery->serial);
ffCfDictGetString(properties, CFSTR(kIOPMPSManufacturerKey), &battery->manufacturer);
if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue)
{
ffStrbufAppendS(&battery->manufacturer, "Apple Inc.");
if (!battery->manufacturer.length)
ffStrbufAppendS(&battery->manufacturer, "Apple Inc.");
ffStrbufAppendS(&battery->technology, "Lithium");
if (!battery->modelName.length)
ffStrbufAppendS(&battery->modelName, "Built-in");
@@ -68,17 +68,28 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
ffStrbufTrimRight(&battery->status, ' ');
ffStrbufTrimRight(&battery->status, ',');
CFDictionaryRef batteryData;
if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL)
int sbdsManufactureDate = 0;
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSManufactureDateKey), &sbdsManufactureDate) == NULL)
{
char manufactureDate[sizeof(uint64_t)];
if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL)
int day = sbdsManufactureDate & 0b11111;
int month = (sbdsManufactureDate >> 5) & 0b1111;
int year = (sbdsManufactureDate >> 9) + 1800;
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
}
else
{
CFDictionaryRef batteryData;
if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL)
{
// https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419
int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8;
int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0');
int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '5');
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
char manufactureDate[sizeof(uint64_t)];
if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL)
{
// https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419
int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8;
int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0');
int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '5');
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
}
}
}
+2 -2
View File
@@ -54,13 +54,13 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r
else if(battio.battinfo.state & ACPI_BATT_STAT_CHARGING)
ffStrbufAppendS(&battery->status, "Charging, ");
if(battio.battinfo.state & ACPI_BATT_STAT_CRITICAL)
ffStrbufAppendS(&battery->status, "Ctritical, ");
ffStrbufAppendS(&battery->status, "Critical, ");
}
int acadStatus;
if (ioctl(acpifd, ACPIIO_ACAD_GET_STATUS, &acadStatus) >= 0 && acadStatus)
{
ffStrbufAppendS(&battery->status, "AC connected");
ffStrbufAppendS(&battery->status, "AC Connected");
}
else
{
+22
View File
@@ -5,6 +5,8 @@
#include <dirent.h>
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-power
static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* options, FFlist* results)
{
uint32_t dirLength = dir->length;
@@ -68,6 +70,26 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
ffStrbufTrimRightSpace(&result->status);
ffStrbufSubstrBefore(dir, dirLength);
// Unknown, Charging, Discharging, Not charging, Full
if (ffStrbufEqualS(&result->status, "Not charging") || ffStrbufEqualS(&result->status, "Full"))
ffStrbufSetStatic(&result->status, "AC Connected");
else if (ffStrbufEqualS(&result->status, "Unknown"))
ffStrbufClear(&result->status);
ffStrbufAppendS(dir, "/capacity_level");
if (ffReadFileBuffer(dir->chars, &tmpBuffer))
{
ffStrbufTrimRightSpace(&result->manufacturer);
if (ffStrbufEqualS(&tmpBuffer, "Critical"))
{
if (result->status.length)
ffStrbufAppendS(&result->status, ", Critical");
else
ffStrbufSetStatic(&result->status, "Critical");
}
}
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->serial);
ffStrbufAppendS(dir, "/serial_number");
if (ffReadFileBuffer(dir->chars, &result->serial))
+3 -3
View File
@@ -203,9 +203,9 @@ const char* detectBySmbios(FFBatteryResult* battery)
}
else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsManufactureDate))
{
uint16_t day = data->SbdsManufactureDate & 0b11111;
uint16_t month = (data->SbdsManufactureDate >> 5) & 0b1111;
uint16_t year = (data->SbdsManufactureDate >> 9) + 1800;
int day = data->SbdsManufactureDate & 0b11111;
int month = (data->SbdsManufactureDate >> 5) & 0b1111;
int year = (data->SbdsManufactureDate >> 9) + 1800;
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include "fastfetch.h"
typedef struct FFCameraResult
{
FFstrbuf name;
FFstrbuf vendor;
FFstrbuf id;
FFstrbuf colorspace;
uint32_t width;
uint32_t height;
} FFCameraResult;
const char* ffDetectCamera(FFlist* result /* list of FFCameraResult */);
+61
View File
@@ -0,0 +1,61 @@
#include "camera.h"
#include "common/processing.h"
#include "common/properties.h"
#define FF_TERMUX_API_PATH FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api"
#define FF_TERMUX_API_PARAM "CameraInfo"
static inline void wrapYyjsonFree(yyjson_doc** doc)
{
assert(doc);
if (*doc)
yyjson_doc_free(*doc);
}
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
if(ffProcessAppendStdOut(&buffer, (char* const[]){
FF_TERMUX_API_PATH,
FF_TERMUX_API_PARAM,
NULL
}))
return "Starting `" FF_TERMUX_API_PATH " " FF_TERMUX_API_PARAM "` failed";
yyjson_doc* __attribute__((__cleanup__(wrapYyjsonFree))) doc = yyjson_read_opts(buffer.chars, buffer.length, 0, NULL, NULL);
if (!doc)
return "Failed to parse camera info";
yyjson_val* root = yyjson_doc_get_root(doc);
if (!yyjson_is_arr(root))
return "Camera info result is not a JSON array";
yyjson_val* device;
size_t idx, max;
yyjson_arr_foreach(root, idx, max, device)
{
FFCameraResult* camera = (FFCameraResult*) ffListAdd(result);
{
const char* facing = yyjson_get_str(yyjson_obj_get(device, "facing"));
if (facing)
ffStrbufInitF(&camera->name, "builtin-%s", facing);
else
ffStrbufInitStatic(&camera->name, "Unknown");
}
ffStrbufInit(&camera->vendor);
ffStrbufInitS(&camera->id, yyjson_get_str(yyjson_obj_get(device, "id")));
yyjson_val* sizes = yyjson_arr_get_first(yyjson_obj_get(device, "jpeg_output_sizes"));
if (yyjson_is_obj(sizes))
{
camera->width = (uint32_t) yyjson_get_uint(yyjson_obj_get(sizes, "width"));
camera->height = (uint32_t) yyjson_get_uint(yyjson_obj_get(sizes, "height"));
}
else
camera->width = camera->height = 0;
ffStrbufInit(&camera->colorspace);
}
return NULL;
}
+31
View File
@@ -0,0 +1,31 @@
#include "camera.h"
#import <AVFoundation/AVCaptureDevice.h>
const char* ffDetectCamera(FFlist* result)
{
AVCaptureDeviceDiscoverySession* session = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionUnspecified];
if (!session)
return "Failed to create AVCaptureDeviceDiscoverySession";
for (AVCaptureDevice* device in session.devices)
{
FFCameraResult* camera = (FFCameraResult*) ffListAdd(result);
ffStrbufInitS(&camera->name, device.localizedName.UTF8String);
ffStrbufInitS(&camera->vendor, device.manufacturer.UTF8String);
ffStrbufInitS(&camera->id, device.uniqueID.UTF8String);
switch (device.activeColorSpace)
{
case AVCaptureColorSpace_sRGB: ffStrbufInitStatic(&camera->colorspace, "sRGB"); break;
case AVCaptureColorSpace_P3_D65: ffStrbufInitStatic(&camera->colorspace, "P3-D65"); break;
case 2 /*AVCaptureColorSpace_HLG_BT2020*/: ffStrbufInitStatic(&camera->colorspace, "BT2020-HLG"); break;
case 3 /*AVCaptureColorSpace_AppleLog*/: ffStrbufInitStatic(&camera->colorspace, "AppleLog"); break;
}
CMVideoDimensions size = CMVideoFormatDescriptionGetDimensions(device.activeFormat.formatDescription);
camera->width = size.width < 0 ? 0 : (uint32_t) size.width;
camera->height = size.height < 0 ? 0 : (uint32_t) size.height;
}
return NULL;
}
+61
View File
@@ -0,0 +1,61 @@
#include "camera.h"
#include "common/io/io.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#if __has_include(<linux/videodev2.h>)
#include <linux/videodev2.h>
#endif
const char* ffDetectCamera(FFlist* result)
{
#if __has_include(<linux/videodev2.h>)
char path[] = "/dev/videoN";
for (uint32_t i = 0; i <= 9; ++i)
{
path[sizeof(path) - 2] = (char) (i + '0');
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY);
if (fd < 0)
break;
struct v4l2_capability cap = {};
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
continue;
struct v4l2_format fmt = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE };
if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0)
continue;
FFCameraResult* camera = (FFCameraResult*) ffListAdd(result);
ffStrbufInitS(&camera->name, (const char*) cap.card);
ffStrbufInit(&camera->vendor);
ffStrbufInitS(&camera->id, (const char*) cap.bus_info);
switch (fmt.fmt.pix.colorspace)
{
case V4L2_COLORSPACE_SMPTE170M: ffStrbufInitStatic(&camera->colorspace, "SMPTE 170M"); break;
case V4L2_COLORSPACE_SMPTE240M: ffStrbufInitStatic(&camera->colorspace, "SMPTE 240M"); break;
case V4L2_COLORSPACE_BT878: ffStrbufInitStatic(&camera->colorspace, "BT.808"); break;
case V4L2_COLORSPACE_470_SYSTEM_M: ffStrbufInitStatic(&camera->colorspace, "NTSC"); break;
case V4L2_COLORSPACE_470_SYSTEM_BG: ffStrbufInitStatic(&camera->colorspace, "EBU 3213"); break;
case V4L2_COLORSPACE_JPEG: ffStrbufInitStatic(&camera->colorspace, "JPEG"); break;
case V4L2_COLORSPACE_REC709:
case V4L2_COLORSPACE_SRGB: ffStrbufInitStatic(&camera->colorspace, "sRGB"); break;
case V4L2_COLORSPACE_OPRGB: ffStrbufInitStatic(&camera->colorspace, "Adobe RGB"); break;
case V4L2_COLORSPACE_BT2020: ffStrbufInitStatic(&camera->colorspace, "BT.2020"); break;
case V4L2_COLORSPACE_RAW: ffStrbufInitStatic(&camera->colorspace, "RAW"); break;
case V4L2_COLORSPACE_DCI_P3: ffStrbufInitStatic(&camera->colorspace, "DCI-P3"); break;
default: ffStrbufInit(&camera->colorspace); break;
}
camera->width = fmt.fmt.pix.width;
camera->height = fmt.fmt.pix.height;
}
return NULL;
#else
FF_UNUSED(result);
return "Fastfetch was compiled without <linux/videodev2.h>";
#endif
}
+129
View File
@@ -0,0 +1,129 @@
extern "C" {
#include "camera.h"
#include "common/library.h"
}
#include "util/windows/com.hpp"
#include "util/windows/unicode.hpp"
#include <initguid.h>
#include <mfapi.h>
#include <mfidl.h>
template <typename Fn>
struct on_scope_exit {
on_scope_exit(Fn &&fn): _fn(std::move(fn)) {}
~on_scope_exit() { this->_fn(); }
private:
Fn _fn;
};
extern "C"
const char* ffDetectCamera(FF_MAYBE_UNUSED FFlist* result)
{
FF_LIBRARY_LOAD(mfplat, NULL, "dlopen mfplat" FF_LIBRARY_EXTENSION " failed", "mfplat" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mfplat, MFCreateAttributes)
FF_LIBRARY_LOAD(mf, NULL, "dlopen mf" FF_LIBRARY_EXTENSION " failed", "mf" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mf, MFEnumDeviceSources)
const char* error = ffInitCom();
if (error)
return error;
IMFAttributes* FF_AUTO_RELEASE_COM_OBJECT attrs = nullptr;
if (FAILED(ffMFCreateAttributes(&attrs, 1)))
return "MFCreateAttributes() failed";
if (FAILED(attrs->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
)))
return "SetGUID(MF_*) failed";
IMFActivate** devices = NULL;
uint32_t count;
if (FAILED(ffMFEnumDeviceSources(attrs, &devices, &count)))
return "MFEnumDeviceSources() failed";
for (uint32_t i = 0; i < count; i++)
{
IMFActivate* device = devices[i];
wchar_t buffer[256];
uint32_t length = 0;
if (FAILED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, buffer, sizeof(buffer), &length)) || length == 0)
continue;
FFCameraResult* camera = (FFCameraResult*) ffListAdd(result);
ffStrbufInitNWS(&camera->name, length, buffer);
ffStrbufInit(&camera->colorspace);
ffStrbufInit(&camera->vendor);
ffStrbufInit(&camera->id);
camera->width = 0;
camera->height = 0;
if (SUCCEEDED(device->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, buffer, sizeof(buffer), &length)) && length > 0)
ffStrbufSetNWS(&camera->id, length, buffer);
IMFMediaSource* FF_AUTO_RELEASE_COM_OBJECT source = nullptr;
if (FAILED(device->ActivateObject(IID_PPV_ARGS(&source))))
continue;
on_scope_exit destroySource([&] { source->Shutdown(); });
IMFPresentationDescriptor* FF_AUTO_RELEASE_COM_OBJECT pd = nullptr;
if (FAILED(source->CreatePresentationDescriptor(&pd)))
continue;
IMFStreamDescriptor* FF_AUTO_RELEASE_COM_OBJECT sd = NULL;
BOOL selected;
if (FAILED(pd->GetStreamDescriptorByIndex(0, &selected, &sd)))
continue;
IMFMediaTypeHandler* FF_AUTO_RELEASE_COM_OBJECT handler = NULL;
if (FAILED(sd->GetMediaTypeHandler(&handler)))
continue;
DWORD mediaTypeCount;
if (FAILED(handler->GetMediaTypeCount(&mediaTypeCount)))
continue;
// Assume first type is the maximum resolution
IMFMediaType* FF_AUTO_RELEASE_COM_OBJECT type = NULL;
for (DWORD idx = 0; SUCCEEDED(handler->GetMediaTypeByIndex(idx, &type)); ++idx)
{
GUID majorType;
if (FAILED(type->GetMajorType(&majorType)) || majorType != MFMediaType_Video)
continue;
MFVideoPrimaries primaries;
static_assert(sizeof(primaries) == sizeof(uint32_t), "");
if (SUCCEEDED(type->GetUINT32(MF_MT_VIDEO_PRIMARIES, (uint32_t*) &primaries)))
{
switch (primaries)
{
case MFVideoPrimaries_BT709: ffStrbufSetStatic(&camera->colorspace, "sRGB"); break;
case MFVideoPrimaries_BT470_2_SysM:
case MFVideoPrimaries_BT470_2_SysBG: ffStrbufSetStatic(&camera->colorspace, "NTSC"); break;
case MFVideoPrimaries_SMPTE170M: ffStrbufSetStatic(&camera->colorspace, "SMPTE 170M"); break;
case MFVideoPrimaries_SMPTE240M: ffStrbufSetStatic(&camera->colorspace, "SMPTE 240M"); break;
case MFVideoPrimaries_EBU3213: ffStrbufSetStatic(&camera->colorspace, "EBU 3213"); break;
case MFVideoPrimaries_SMPTE_C: ffStrbufSetStatic(&camera->colorspace, "SMPTE C"); break;
case MFVideoPrimaries_BT2020: ffStrbufSetStatic(&camera->colorspace, "BT.2020"); break;
case MFVideoPrimaries_XYZ: ffStrbufSetStatic(&camera->colorspace, "XYZ"); break;
case MFVideoPrimaries_DCI_P3: ffStrbufSetStatic(&camera->colorspace, "DCI-P3"); break;
case MFVideoPrimaries_ACES: ffStrbufSetStatic(&camera->colorspace, "ACES"); break;
default: break;
}
}
MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &camera->width, &camera->height);
break;
}
}
CoTaskMemFree(devices);
return nullptr;
}
+83 -1
View File
@@ -4,6 +4,7 @@
#include "common/properties.h"
#include "detection/temps/temps_linux.h"
#include "util/mallocHelper.h"
#include "util/stringUtils.h"
#include <sys/sysinfo.h>
#include <stdlib.h>
@@ -34,6 +35,10 @@ static const char* parseCpuInfo(FFCPUResult* cpu, FFstrbuf* physicalCoresBuffer,
FF_AUTO_FREE char* line = NULL;
size_t len = 0;
#ifdef __aarch64__
FF_STRBUF_AUTO_DESTROY implementer = ffStrbufCreate();
#endif
while(getline(&line, &len, cpuinfo) != -1)
{
//Stop after the first CPU
@@ -47,12 +52,36 @@ static const char* parseCpuInfo(FFCPUResult* cpu, FFstrbuf* physicalCoresBuffer,
ffParsePropLine(line, "cpu MHz :", cpuMHz) ||
ffParsePropLine(line, "isa :", cpuIsa) ||
ffParsePropLine(line, "uarch :", cpuUarch) ||
#ifdef __aarch64__
(cpu->vendor.length == 0 && ffParsePropLine(line, "CPU implementer :", &implementer)) ||
#endif
(cpu->name.length == 0 && ffParsePropLine(line, "Hardware :", &cpu->name)) || //For Android devices
(cpu->name.length == 0 && ffParsePropLine(line, "cpu :", &cpu->name)) || //For POWER
(cpu->name.length == 0 && ffParsePropLine(line, "cpu model :", &cpu->name)) //For MIPS
);
}
#ifdef __aarch64__
// https://github.com/util-linux/util-linux/blob/2cd89de14549d2b2c079a4f8b73f75500d229fee/sys-utils/lscpu-arm.c#L286
if (cpu->vendor.length == 0 && implementer.length > 2 /* 0xX */)
{
uint32_t implId = (uint32_t) strtoul(implementer.chars, NULL, 16);
switch (implId)
{
case 0x41: ffStrbufSetStatic(&cpu->vendor, "ARM"); break;
case 0x42: ffStrbufSetStatic(&cpu->vendor, "Broadcom"); break;
case 0x48: ffStrbufSetStatic(&cpu->vendor, "HiSilicon"); break;
case 0x4e: ffStrbufSetStatic(&cpu->vendor, "Nvidia"); break;
case 0x51: ffStrbufSetStatic(&cpu->vendor, "Qualcomm"); break;
case 0x53: ffStrbufSetStatic(&cpu->vendor, "Samsung"); break;
case 0x61: ffStrbufSetStatic(&cpu->vendor, "Apple"); break;
case 0x69: ffStrbufSetStatic(&cpu->vendor, "Intel"); break;
}
}
#endif
return NULL;
}
@@ -121,6 +150,44 @@ static void parseIsa(FFstrbuf* cpuIsa)
}
}
void detectAsahi(FFCPUResult* cpu)
{
// In Asahi Linux, reading /proc/device-tree/compatible gives
// information on the device model. It consists of 3 NUL terminated
// strings, the second of which gives the actual SoC model. But it
// is not the marketing name, i.e. for M2 there is "apple,t8112" in
// the compatible string.
if (cpu->name.length == 0 && ffStrbufEqualS(&cpu->vendor, "Apple"))
{
char content[32];
ssize_t length = ffReadFileData("/proc/device-tree/compatible", sizeof(content), content);
if (length <= 0) return;
// get the second NUL terminated string
char* modelName = memchr(content, '\0', (size_t) length) + 1;
if (modelName - content < length && ffStrStartsWith(modelName, "apple,t"))
{
// https://github.com/AsahiLinux/docs/wiki/Codenames
switch (strtoul(modelName + strlen("apple,t"), NULL, 10))
{
case 8103: ffStrbufSetStatic(&cpu->name, "Apple M1"); break;
case 6000: ffStrbufSetStatic(&cpu->name, "Apple M1 Pro"); break;
case 6001: ffStrbufSetStatic(&cpu->name, "Apple M1 Max"); break;
case 6002: ffStrbufSetStatic(&cpu->name, "Apple M1 Ultra"); break;
case 8112: ffStrbufSetStatic(&cpu->name, "Apple M2"); break;
case 6020: ffStrbufSetStatic(&cpu->name, "Apple M2 Pro"); break;
case 6021: ffStrbufSetStatic(&cpu->name, "Apple M2 Max"); break;
case 6022: ffStrbufSetStatic(&cpu->name, "Apple M2 Ultra"); break;
case 8122: ffStrbufSetStatic(&cpu->name, "Apple M3"); break;
case 6030: ffStrbufSetStatic(&cpu->name, "Apple M3 Pro"); break;
case 6031:
case 6034: ffStrbufSetStatic(&cpu->name, "Apple M3 Max"); break;
default: ffStrbufSetStatic(&cpu->name, "Apple Silicon"); break;
}
}
}
}
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
{
cpu->temperature = options->temp ? detectCPUTemp() : FF_CPU_TEMP_UNSET;
@@ -167,6 +234,10 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
detectAndroid(cpu);
#endif
#if defined(__linux__) && defined(__aarch64__)
detectAsahi(cpu);
#endif
if (cpu->name.length == 0)
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
@@ -191,8 +262,14 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
ffStrbufAppendS(&cpu->vendor, pstart);
}
pstart = pend + 1;
if (pstart >= buffer.chars + buffer.length)
return NULL;
}
}
else
{
pstart = buffer.chars;
}
}
while ((pstart = strstr(pstart, "Model name:")))
@@ -207,7 +284,10 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
if (*pstart == '-')
{
ffStrbufAppendS(&cpu->name, "Unknown");
if (cpu->vendor.length > 0)
ffStrbufAppend(&cpu->name, &cpu->vendor);
else
ffStrbufAppendS(&cpu->name, "Unknown");
++pstart;
continue;
}
@@ -222,6 +302,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
}
pstart = pend + 1;
if (pstart >= buffer.chars + buffer.length)
return NULL;
}
}
}
+3 -3
View File
@@ -2,9 +2,9 @@
const char* ffDetectDisksImpl(FFlist* disks);
static int compareDisks(const void* disk1, const void* disk2)
static int compareDisks(const FFDisk* disk1, const FFDisk* disk2)
{
return ffStrbufCompAlphabetically(&((const FFDisk*) disk1)->mountpoint, &((const FFDisk*) disk2)->mountpoint);
return ffStrbufComp(&disk1->mountpoint, &disk2->mountpoint);
}
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks)
@@ -18,7 +18,7 @@ const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks)
// For example for /boot/efi/bootmgr we need to check /boot/efi before /boot
//Note that we sort alphabetically here for a better ordering when printing the list,
// so the check must be done in reverse order
ffListSort(disks, compareDisks);
ffListSort(disks, (void*) compareDisks);
FF_LIST_FOR_EACH(FFDisk, disk, *disks)
{
if(disk->bytesTotal == 0)
+4
View File
@@ -41,6 +41,10 @@ static bool isPhysicalDevice(const struct mntent* device)
if(!ffStrStartsWith(device->mnt_fsname, "/dev/"))
return false;
//#731
if(ffStrEquals(device->mnt_type, "bcachefs"))
return true;
if(
ffStrStartsWith(device->mnt_fsname + 5, "loop") || //Ignore loop devices
ffStrStartsWith(device->mnt_fsname + 5, "ram") || //Ignore ram devices
+11
View File
@@ -9,6 +9,8 @@ static uint64_t time1;
void ffPrepareDiskIO(FFDiskIOOptions* options)
{
if (options->detectTotal) return;
ffListInit(&ioCounters1, sizeof(FFDiskIOResult));
ffDiskIOGetIoCounters(&ioCounters1, options);
time1 = ffTimeGetNow();
@@ -17,6 +19,15 @@ void ffPrepareDiskIO(FFDiskIOOptions* options)
const char* ffDetectDiskIO(FFlist* result, FFDiskIOOptions* options)
{
const char* error = NULL;
if (options->detectTotal)
{
error = ffDiskIOGetIoCounters(result, options);
if (error)
return error;
return NULL;
}
if (time1 == 0)
{
ffListInit(&ioCounters1, sizeof(FFDiskIOResult));
+2 -1
View File
@@ -5,6 +5,7 @@
#include <ctype.h>
#include <limits.h>
#include <inttypes.h>
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
{
@@ -89,7 +90,7 @@ const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
ssize_t fileSize = ffReadFileData(pathSysBlock, sizeof(sysBlockStat) - 1, sysBlockStat);
if (fileSize <= 0) continue;
sysBlockStat[fileSize] = '\0';
if (sscanf(sysBlockStat, "%lu%*u%lu%*u%lu%*u%lu%*u", &nRead, &sectorRead, &nWritten, &sectorWritten) <= 0)
if (sscanf(sysBlockStat, "%" PRIu64 "%*u%" PRIu64 "%*u%" PRIu64 "%*u%" PRIu64 "%*u", &nRead, &sectorRead, &nWritten, &sectorWritten) <= 0)
continue;
}
+1 -1
View File
@@ -46,7 +46,7 @@ static const char* drmParseSysfs(FFDisplayServerResult* result)
continue;
}
uint32_t width = 0, height = 0;
unsigned width = 0, height = 0;
int scanned = sscanf(modes, "%ux%u", &width, &height);
if(scanned == 2 && width > 0 && height > 0)
+6
View File
@@ -6,6 +6,8 @@ const char* FF_GPU_VENDOR_NAME_APPLE = "Apple";
const char* FF_GPU_VENDOR_NAME_AMD = "AMD";
const char* FF_GPU_VENDOR_NAME_INTEL = "Intel";
const char* FF_GPU_VENDOR_NAME_NVIDIA = "NVIDIA";
const char* FF_GPU_VENDOR_NAME_QUALCOMM = "Qualcomm";
const char* FF_GPU_VENDOR_NAME_MTK = "MTK";
const char* FF_GPU_VENDOR_NAME_VMWARE = "VMware";
const char* FF_GPU_VENDOR_NAME_PARALLEL = "Parallel";
const char* FF_GPU_VENDOR_NAME_MICROSOFT = "Microsoft";
@@ -33,6 +35,10 @@ const char* ffGetGPUVendorString(unsigned vendorId)
return FF_GPU_VENDOR_NAME_INTEL;
else if(arrayContains((const unsigned[]) {0x0955, 0x10de, 0x12d2}, vendorId, 3))
return FF_GPU_VENDOR_NAME_NVIDIA;
else if(arrayContains((const unsigned[]) {0x5143}, vendorId, 1))
return FF_GPU_VENDOR_NAME_QUALCOMM;
else if(arrayContains((const unsigned[]) {0x14c3}, vendorId, 1))
return FF_GPU_VENDOR_NAME_MTK;
else if(arrayContains((const unsigned[]) {0x15ad}, vendorId, 1))
return FF_GPU_VENDOR_NAME_VMWARE;
else if(arrayContains((const unsigned[]) {0x1af4}, vendorId, 1))
+4
View File
@@ -42,3 +42,7 @@ const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result);
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus);
const char* ffGetGPUVendorString(unsigned vendorId);
#if defined(__linux__) || defined(__FreeBSD__)
void ffGPUParsePciIds(FFstrbuf* content, uint8_t subclass, uint16_t vendor, uint16_t device, uint16_t subVendor, uint16_t subDevice, FFGPUResult* gpu);
#endif
+1 -1
View File
@@ -32,7 +32,7 @@ const char* ffGpuDetectMetal(FFlist* gpus)
else if ([device supportsFamily:MTLGPUFamilyCommon1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
if (gpu->type == device.hasUnifiedMemory)
if (device.hasUnifiedMemory)
{
gpu->type = FF_GPU_TYPE_INTEGRATED;
gpu->shared.total = device.recommendedMaxWorkingSetSize;
+106
View File
@@ -0,0 +1,106 @@
#include "gpu_driver_specific.h"
#include "common/io/io.h"
#include "common/properties.h"
#include "3rdparty/nvml/nvml.h"
#include "util/mallocHelper.h"
#include <dev/pci/pcireg.h>
#include <sys/pciio.h>
#include <fcntl.h>
#include <paths.h>
static bool loadPciIds(FFstrbuf* pciids)
{
// https://github.com/freebsd/freebsd-src/blob/main/usr.sbin/pciconf/pathnames.h
ffReadFileBuffer(_PATH_LOCALBASE "/share/pciids/pci.ids", pciids);
if (pciids->length > 0) return true;
ffReadFileBuffer("/usr/share/pciids/pci.ids", pciids);
if (pciids->length > 0) return true;
return false;
}
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
{
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY, 0);
struct pci_conf confs[128];
struct pci_match_conf match = {
.pc_class = PCIC_DISPLAY,
.flags = PCI_GETCONF_MATCH_CLASS,
};
struct pci_conf_io pcio = {
.pat_buf_len = sizeof(match),
.num_patterns = 1,
.patterns = &match,
.match_buf_len = sizeof(confs),
.matches = confs,
};
if (ioctl(fd, PCIOCGETCONF, &pcio) < 0)
return "ioctl(fd, PCIOCGETCONF, &pc) failed";
if (pcio.status == PCI_GETCONF_ERROR)
return "ioctl(fd, PCIOCGETCONF, &pc) returned error";
FF_STRBUF_AUTO_DESTROY pciids = ffStrbufCreate();
for (uint32_t i = 0; i < pcio.num_matches; ++i)
{
struct pci_conf* pc = &confs[i];
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString(pc->pc_vendor));
ffStrbufInit(&gpu->name);
ffStrbufInitS(&gpu->driver, pc->pd_name);
ffStrbufInit(&gpu->platformApi);
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ((uint64_t) pc->pc_sel.pc_domain << 6) | ((uint64_t) pc->pc_sel.pc_bus << 4) | ((uint64_t) pc->pc_sel.pc_dev << 2) | pc->pc_sel.pc_func;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
{
char query[32];
snprintf(query, sizeof(query), "%X,\t%X,", (unsigned) pc->pc_device, (unsigned) pc->pc_revid);
ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name);
}
if (gpu->name.length == 0)
{
if (pciids.length == 0)
loadPciIds(&pciids);
ffGPUParsePciIds(&pciids, pc->pc_subclass, pc->pc_vendor, pc->pc_device, pc->pc_subvendor, pc->pc_subdevice, gpu);
}
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
{
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = {
.domain = (uint32_t) pc->pc_sel.pc_domain,
.bus = pc->pc_sel.pc_bus,
.device = pc->pc_sel.pc_dev,
.func = pc->pc_sel.pc_func,
},
}, (FFGpuDriverResult) {
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.type = &gpu->type,
.frequency = &gpu->frequency,
}, "libnvidia-ml.so");
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
}
return NULL;
}
+140 -308
View File
@@ -1,154 +1,25 @@
#include "detection/gpu/gpu.h"
#include "detection/vulkan/vulkan.h"
#include "detection/temps/temps_linux.h"
#include "common/io/io.h"
#include "common/properties.h"
#include "util/stringUtils.h"
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
#include "detection/gpu/gpu_driver_specific.h"
#endif
#ifdef FF_HAVE_LIBPCI
#include "common/io/io.h"
#include "common/library.h"
#include "common/properties.h"
#include "common/parsing.h"
#include "detection/temps/temps_linux.h"
#include "util/stringUtils.h"
#include <string.h>
#include <unistd.h>
#include <pci/pci.h>
#include <setjmp.h>
#include <inttypes.h>
// Fix building on Ubuntu 20.04
#ifndef PCI_IORESOURCE_MEM
#define PCI_IORESOURCE_MEM 0x00000200
#endif
#ifndef PCI_IORESOURCE_PREFETCH
#define PCI_IORESOURCE_PREFETCH 0x00002000
#endif
typedef struct PCIData
{
struct pci_access* access;
FF_LIBRARY_SYMBOL(pci_fill_info)
FF_LIBRARY_SYMBOL(pci_read_byte)
FF_LIBRARY_SYMBOL(pci_lookup_name)
FF_LIBRARY_SYMBOL(pci_get_param)
#if PCI_LIB_VERSION >= 0x030800
FF_LIBRARY_SYMBOL(pci_get_string_property)
#endif
} PCIData;
static void pciDetectVendorName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
{
ffStrbufSetStatic(&gpu->vendor, ffGetGPUVendorString(device->vendor_id));
if(gpu->vendor.length > 0)
return;
ffStrbufEnsureFree(&gpu->vendor, 255);
pci->ffpci_lookup_name(pci->access, gpu->vendor.chars, (int) gpu->vendor.allocated, PCI_LOOKUP_VENDOR, device->vendor_id);
ffStrbufRecalculateLength(&gpu->vendor);
if(ffStrbufContainIgnCaseS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "Intel"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "NVIDIA"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
else if(ffStrbufContainIgnCaseS(&gpu->vendor, "Apple"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
}
static void drmDetectDeviceName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
{
u8 revId = 0;
bool revIdSet = false;
#if PCI_LIB_VERSION >= 0x030800
revIdSet = pci->ffpci_fill_info(device, PCI_FILL_CLASS_EXT) & PCI_FILL_CLASS_EXT;
if(revIdSet)
revId = device->rev_id;
#endif
if(!revIdSet)
{
#ifdef __FreeBSD__
return;
#else
revId = pci->ffpci_read_byte(device, PCI_REVISION_ID);
#endif
}
FF_STRBUF_AUTO_DESTROY query = ffStrbufCreateF("%X, %X,", device->device_id, revId);
ffParsePropFileData("libdrm/amdgpu.ids", query.chars, &gpu->name);
const char* removeStrings[] = {
"AMD ", "ATI ",
" (TM)", "(TM)",
" Graphics Adapter", " Graphics", " Series", " Edition"
};
ffStrbufRemoveStrings(&gpu->name, sizeof(removeStrings) / sizeof(removeStrings[0]), removeStrings);
}
static void pciDetectDeviceName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
{
if(ffStrbufEqualS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD))
{
drmDetectDeviceName(gpu, pci, device);
if(gpu->name.length > 0)
return;
}
ffStrbufEnsureFree(&gpu->name, 255);
pci->ffpci_lookup_name(pci->access, gpu->name.chars, (int) gpu->name.allocated, PCI_LOOKUP_DEVICE, device->vendor_id, device->device_id);
ffStrbufRecalculateLength(&gpu->name);
uint32_t openingBracket = ffStrbufFirstIndexC(&gpu->name, '[');
uint32_t closingBracket = ffStrbufNextIndexC(&gpu->name, openingBracket, ']');
if(closingBracket < gpu->name.length)
{
ffStrbufSubstrBefore(&gpu->name, closingBracket);
ffStrbufSubstrAfter(&gpu->name, openingBracket);
}
}
static void pciDetectDriverName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device)
{
#if PCI_LIB_VERSION >= 0x030800
pci->ffpci_fill_info(device, PCI_FILL_DRIVER);
ffStrbufAppendS(&gpu->driver, pci->ffpci_get_string_property(device, PCI_FILL_DRIVER));
#endif
const char* base = pci->ffpci_get_param(pci->access, "sysfs.path");
if(!ffStrSet(base))
return;
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateF("%s/devices/%04x:%02x:%02x.%d/driver", base, device->domain, device->bus, device->dev, device->func);
if (gpu->driver.length == 0)
{
ffStrbufEnsureFree(&gpu->driver, 1023);
ssize_t resultLength = readlink(path.chars, gpu->driver.chars, gpu->driver.allocated - 1); //-1 for null terminator
if(resultLength > 0)
{
gpu->driver.length = (uint32_t) resultLength;
gpu->driver.chars[resultLength] = '\0';
ffStrbufSubstrAfterLastC(&gpu->driver, '/');
}
}
ffStrbufAppendC(&gpu->driver, ' ');
ffStrbufAppendS(&path, "/module/version");
ffAppendFileBuffer(path.chars, &gpu->driver);
ffStrbufTrimRightSpace(&gpu->driver);
}
FF_MAYBE_UNUSED static void pciDetectTemp(FFGPUResult* gpu, struct pci_dev* device)
FF_MAYBE_UNUSED static void pciDetectTemp(FFGPUResult* gpu, uint32_t deviceClass)
{
const FFlist* tempsResult = ffDetectTemps();
FF_LIST_FOR_EACH(FFTempValue, tempValue, *tempsResult)
{
// FIXME: this code doesn't take multiGPUs into count
//The kernel exposes the device class multiplied by 256 for some reason
if(tempValue->deviceClass == device->device_class * 256)
if(tempValue->deviceClass == deviceClass * 256)
{
gpu->temperature = tempValue->value;
return;
@@ -156,195 +27,161 @@ FF_MAYBE_UNUSED static void pciDetectTemp(FFGPUResult* gpu, struct pci_dev* devi
}
}
FF_MAYBE_UNUSED static bool pciDetectMemory(FFGPUResult* gpu, const PCIData* pci, struct pci_dev* device)
static void pciDetectDriver(FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer)
{
gpu->dedicated.used = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
uint32_t flags = (uint32_t) pci->ffpci_fill_info(device, PCI_FILL_IO_FLAGS | PCI_FILL_SIZES);
if (!(flags & PCI_FILL_IO_FLAGS) || !(flags & PCI_FILL_SIZES))
ffStrbufAppendS(pciDir, "/driver");
char pathBuf[PATH_MAX];
ssize_t resultLength = readlink(pciDir->chars, pathBuf, sizeof(pathBuf));
if(resultLength > 0)
{
gpu->dedicated.total = gpu->shared.total = FF_GPU_VMEM_SIZE_UNSET;
return false;
const char* slash = memrchr(pathBuf, '/', (size_t) resultLength);
if (slash)
{
slash++;
ffStrbufSetNS(&gpu->driver, (uint32_t) (resultLength - (slash - pathBuf)), slash);
}
ffStrbufAppendS(pciDir, "/module/version");
if (ffReadFileBuffer(pciDir->chars, buffer))
{
ffStrbufTrimRightSpace(buffer);
ffStrbufAppendC(&gpu->driver, ' ');
ffStrbufAppend(&gpu->driver, buffer);
}
}
gpu->dedicated.total = gpu->shared.total = 0;
for (uint32_t i = 0; i < sizeof(device->size) / sizeof(device->size[0]); i++)
{
if (!(device->flags[i] & PCI_IORESOURCE_MEM)) continue;
// Assume dedicated memories are prefetchable
// At least it's true for my laptop
if (device->flags[i] & PCI_IORESOURCE_PREFETCH)
gpu->dedicated.total += device->size[i];
else
gpu->shared.total += device->size[i];
}
if (gpu->dedicated.total == 0 && gpu->shared.total == 0)
{
gpu->dedicated.total = gpu->shared.total = FF_GPU_VMEM_SIZE_UNSET;
return false;
}
return true;
}
FF_MAYBE_UNUSED static void pciDetectType(FFGPUResult* gpu)
static bool loadPciIds(FFstrbuf* pciids)
{
//There is no straightforward way to detect the type of a GPU.
//The approach taken here is to look at the memory sizes of the device.
//Since integrated GPUs usually use the system ram, they don't have expansive ROMs
//and their memory sizes are usually smaller than 1GB.
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
{
gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 // 1GB
? FF_GPU_TYPE_DISCRETE
: FF_GPU_TYPE_INTEGRATED;
}
else
gpu->type = FF_GPU_TYPE_UNKNOWN;
}
ffReadFileBuffer("/usr/share/hwdata/pci.ids", pciids);
if (pciids->length > 0) return true;
static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* results, PCIData* pci, struct pci_dev* device)
{
pci->ffpci_fill_info(device, PCI_FILL_CLASS);
ffReadFileBuffer("/usr/share/misc/pci.ids", pciids); // debian?
if (pciids->length > 0) return true;
char class[1024];
pci->ffpci_lookup_name(pci->access, class, sizeof(class) - 1, PCI_LOOKUP_CLASS, device->device_class);
ffReadFileBuffer("/usr/local/share/hwdata/pci.ids", pciids);
if (pciids->length > 0) return true;
if(
//https://pci-ids.ucw.cz/read/PD/03
strcasecmp("VGA compatible controller", class) != 0 &&
strcasecmp("XGA compatible controller", class) != 0 &&
strcasecmp("3D controller", class) != 0 &&
strcasecmp("Display controller", class) != 0
) return;
pci->ffpci_fill_info(device, PCI_FILL_IDENT);
FFGPUResult* gpu = ffListAdd(results);
ffStrbufInit(&gpu->platformApi);
ffStrbufInit(&gpu->vendor);
pciDetectVendorName(gpu, pci, device);
ffStrbufInit(&gpu->name);
pciDetectDeviceName(gpu, pci, device);
ffStrbufInit(&gpu->driver);
pciDetectDriverName(gpu, pci, device);
#if FF_USE_PCI_MEMORY
// Libpci reports at least 2 false results (#495, #497)
pciDetectMemory(gpu, pci, device);
pciDetectType(gpu);
#else
gpu->dedicated.used = gpu->shared.used = gpu->dedicated.total = gpu->shared.total = FF_GPU_VMEM_SIZE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
#endif
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
{
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = {
.domain = (uint32_t) device->domain,
.bus = device->bus,
.device = device->dev,
.func = device->func,
},
}, (FFGpuDriverResult) {
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.type = &gpu->type,
.frequency = &gpu->frequency,
}, "libnvidia-ml.so");
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
#ifdef __linux__
if(options->temp && gpu->temperature != gpu->temperature)
pciDetectTemp(gpu, device);
#endif
}
jmp_buf pciInitJmpBuf;
static void __attribute__((__noreturn__))
handlePciInitError(FF_MAYBE_UNUSED char *msg, ...)
{
longjmp(pciInitJmpBuf, 1);
}
// https://github.com/pciutils/pciutils/blob/bca0412843fa650c749128ade03f35ab3e8fe2b9/lib/init.c#L186
static void __attribute__((__noreturn__))
handlePciGenericError(char *msg, ...)
{
va_list args;
va_start(args, msg);
fputs("pcilib: ", stderr);
vfprintf(stderr, msg, args);
va_end(args);
fputc('\n', stderr);
exit(1);
}
static void handlePciWarning(FF_MAYBE_UNUSED char *msg, ...)
{
// noop
return false;
}
static const char* pciDetectGPUs(const FFGPUOptions* options, FFlist* gpus)
{
PCIData pci;
//https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-bus-pci
const char* pciDirPath = "/sys/bus/pci/devices/";
FF_LIBRARY_LOAD(libpci, &instance.config.library.libPCI, "dlopen libpci.so failed", "libpci" FF_LIBRARY_EXTENSION, 4);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libpci, pci_alloc);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libpci, pci_init);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libpci, pci_scan_bus);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libpci, pci_cleanup);
DIR* dirp = opendir(pciDirPath);
if(dirp == NULL)
return "Failed to open `/sys/bus/pci/devices/`";
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_fill_info);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_lookup_name);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_read_byte);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_get_param);
FF_STRBUF_AUTO_DESTROY pciDir = ffStrbufCreateA(64);
ffStrbufAppendS(&pciDir, pciDirPath);
#if PCI_LIB_VERSION >= 0x030800
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libpci, pci, pci_get_string_property);
#endif
const uint32_t pciBaseDirLength = pciDir.length;
pci.access = ffpci_alloc();
pci.access->warning = handlePciWarning;
pci.access->error = handlePciInitError;
if(setjmp(pciInitJmpBuf) == 0) // https://github.com/pciutils/pciutils/issues/136
ffpci_init(pci.access);
else
return "pcilib: Cannot find any working access method.";
pci.access->error = handlePciGenericError; // set back to generic error so we don't mess up error handling in other places
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY pciids = ffStrbufCreate();
ffpci_scan_bus(pci.access);
struct pci_dev* device = pci.access->devices;
while(device != NULL)
struct dirent* entry;
while((entry = readdir(dirp)) != NULL)
{
pciHandleDevice(options, gpus, &pci, device);
device = device->next;
if(entry->d_name[0] == '.')
continue;
ffStrbufSubstrBefore(&pciDir, pciBaseDirLength);
ffStrbufAppendS(&pciDir, entry->d_name);
const uint32_t pciDevDirLength = pciDir.length;
ffStrbufAppendS(&pciDir, "/modalias");
if (!ffReadFileBuffer(pciDir.chars, &buffer))
continue;
ffStrbufSubstrBefore(&pciDir, pciDevDirLength);
uint32_t vendorId, deviceId, subVendorId, subDeviceId;
uint8_t classId, subclassId;
if (sscanf(buffer.chars, "pci:v%8" SCNx32 "d%8" SCNx32 "sv%8" SCNx32 "sd%8" SCNx32 "bc%2" SCNx8 "sc%2" SCNx8, &vendorId, &deviceId, &subVendorId, &subDeviceId, &classId, &subclassId) != 6)
continue;
if (classId != 0x03 /*PCI_BASE_CLASS_DISPLAY*/)
continue;
uint32_t pciDomain, pciBus, pciDevice, pciFunc;
if (sscanf(entry->d_name, "%" SCNx32 ":%" SCNx32 ":%" SCNx32 ".%" SCNx32, &pciDomain, &pciBus, &pciDevice, &pciFunc) != 4)
continue;
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInitStatic(&gpu->vendor, ffGetGPUVendorString((uint16_t) vendorId));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->platformApi);
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ((uint64_t) pciDomain << 6) | ((uint64_t) pciBus << 4) | (deviceId << 2) | pciFunc;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD)
{
ffStrbufAppendS(&pciDir, "/revision");
if (ffReadFileBuffer(pciDir.chars, &buffer))
{
char* pend;
uint64_t revision = strtoul(buffer.chars, &pend, 16);
if (pend != buffer.chars)
{
char query[32];
snprintf(query, sizeof(query), "%X,\t%X,", (unsigned) deviceId, (unsigned) revision);
ffParsePropFileData("libdrm/amdgpu.ids", query, &gpu->name);
}
}
ffStrbufSubstrBefore(&pciDir, pciDevDirLength);
}
if (gpu->name.length == 0)
{
if (!pciids.length)
loadPciIds(&pciids);
ffGPUParsePciIds(&pciids, subclassId, (uint16_t) vendorId, (uint16_t) deviceId, (uint16_t) subVendorId, (uint16_t) subDeviceId, gpu);
}
pciDetectDriver(gpu, &pciDir, &buffer);
ffStrbufSubstrBefore(&pciDir, pciDevDirLength);
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
{
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID,
.pciBusId = {
.domain = pciDomain,
.bus = pciBus,
.device = pciDevice,
.func = pciFunc,
},
}, (FFGpuDriverResult) {
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.type = &gpu->type,
.frequency = &gpu->frequency,
}, "libnvidia-ml.so");
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
#ifdef __linux__
if(options->temp && gpu->temperature != gpu->temperature)
pciDetectTemp(gpu, ((uint32_t) classId << 8) + subclassId);
#endif
}
ffpci_cleanup(pci.access);
return NULL;
}
#endif
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
{
#ifdef FF_HAVE_DIRECTX_HEADERS
@@ -353,10 +190,5 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
return NULL;
#endif
#ifdef FF_HAVE_LIBPCI
return pciDetectGPUs(options, gpus);
#else
FF_UNUSED(options, gpus);
return "fastfetch is built without libpci support";
#endif
return pciDetectGPUs(options, gpus);
}
+81
View File
@@ -0,0 +1,81 @@
#include "gpu.h"
void ffGPUParsePciIds(FFstrbuf* content, uint8_t subclass, uint16_t vendor, uint16_t device, uint16_t subVendor, uint16_t subDevice, FFGPUResult* gpu)
{
if (content->length)
{
char buffer[32];
// Search for vendor
uint32_t len = (uint32_t) snprintf(buffer, sizeof(buffer), "\n%04x ", vendor);
char* start = (char*) memmem(content->chars, content->length, buffer, len);
char* end = content->chars + content->length;
if (start)
{
start += len;
end = memchr(start, '\n', (uint32_t) (end - start));
if (!end)
end = content->chars + content->length;
if (!gpu->vendor.length)
ffStrbufSetNS(&gpu->vendor, (uint32_t) (end - start), start);
start = end; // point to '\n' of vendor
end = start + 1; // point to start of devices
// find the start of next vendor
while (end[0] == '\t' || end[0] == '#')
{
end = strchr(end, '\n');
if (!end)
{
end = content->chars + content->length;
break;
}
else
end++;
}
// Search for device
len = (uint32_t) snprintf(buffer, sizeof(buffer), "\n\t%04x ", device);
start = memmem(start, (size_t) (end - start), buffer, len);
if (start)
{
start += len;
// Search for subvendor and subdevice
len = (uint32_t) snprintf(buffer, sizeof(buffer), "\n\t\t%04x %04x ", subVendor, subDevice);
char* subStart = memmem(start, (size_t) (end - start), buffer, len);
if (subStart)
start = subStart + len;
end = memchr(start, '\n', (uint32_t) (end - start));
if (!end)
end = content->chars + content->length;
char* openingBracket = memchr(start, '[', (uint32_t) (end - start));
if (openingBracket)
{
openingBracket++;
char* closingBracket = memchr(openingBracket, ']', (uint32_t) (end - openingBracket));
if (closingBracket)
ffStrbufSetNS(&gpu->name, (uint32_t) (closingBracket - openingBracket), openingBracket);
}
if (!gpu->name.length)
ffStrbufSetNS(&gpu->name, (uint32_t) (end - start), start);
}
}
}
if (!gpu->name.length)
{
const char* subclassStr;
switch (subclass)
{
case 0 /*PCI_CLASS_DISPLAY_VGA*/: subclassStr = " (VGA compatible)"; break;
case 1 /*PCI_CLASS_DISPLAY_XGA*/: subclassStr = " (XGA compatible)"; break;
case 2 /*PCI_CLASS_DISPLAY_3D*/: subclassStr = " (3D)"; break;
default: subclassStr = ""; break;
}
ffStrbufSetF(&gpu->name, "%s Device %04X%s", gpu->vendor.length ? gpu->vendor.chars : "Unknown", device, subclassStr);
}
}
+1 -1
View File
@@ -77,7 +77,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
// See: https://download.nvidia.com/XFree86/Linux-x86_64/545.23.06/README/supportedchips.html
// displayDevice.DeviceID = MatchingDeviceId "PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1"
uint32_t vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
swscanf(displayDevice.DeviceID, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId);
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
+1
View File
@@ -68,6 +68,7 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
ffStrbufInitStatic(&gpu->platformApi, "DXCore");
ffStrbufInit(&gpu->driver);
uint64_t value = 0;
+11 -49
View File
@@ -1,61 +1,23 @@
#include "detection/locale/locale.h"
#include "common/properties.h"
#include "common/parsing.h"
#include <stdlib.h>
#include <locale.h>
FF_MAYBE_UNUSED
static void getLocaleFromEnv(FFstrbuf* locale)
{
ffStrbufAppendS(locale, getenv("LANG"));
if(locale->length > 0)
return;
ffStrbufAppendS(locale, getenv("LC_ALL"));
if(locale->length > 0)
return;
ffStrbufAppendS(locale, getenv("LC_MESSAGES"));
}
static void getLocaleFromStdFn(FFstrbuf* locale)
{
#ifdef LC_MESSAGES
ffStrbufAppendS(locale, setlocale(LC_MESSAGES, NULL));
if(locale->length > 0)
return;
#endif
ffStrbufAppendS(locale, setlocale(LC_ALL, NULL));
}
void ffDetectLocale(FFstrbuf* result)
{
#if !(defined(__APPLE__) || defined(_WIN32))
ffStrbufAppendS(result, getenv("LC_MESSAGES"));
if(result->length > 0)
return;
//Ubuntu (and deriviates) use a non standard locale file.
//Parse it first, because on distributions where it exists, it takes precedence.
//Otherwise use the standard etc/locale.conf file.
ffParsePropFile(FASTFETCH_TARGET_DIR_ETC"/default/locale", "LANG =", result);
ffStrbufAppendS(result, getenv("LANG"));
if(result->length > 0)
return;
if(result->length > 0)
return;
ffParsePropFile(FASTFETCH_TARGET_DIR_ETC"/locale.conf", "LANG =", result);
if(result->length > 0)
return;
#ifdef LC_MESSAGES
ffStrbufAppendS(result, setlocale(LC_MESSAGES, NULL));
if(result->length > 0)
return;
#endif
#ifndef _WIN32
getLocaleFromEnv(result);
if(result->length > 0)
return;
#endif
getLocaleFromStdFn(result);
ffStrbufAppendS(result, setlocale(LC_ALL, NULL));
}
-5
View File
@@ -9,10 +9,5 @@ void ffDetectLocale(FFstrbuf* result)
wchar_t name[LOCALE_NAME_MAX_LENGTH];
int size = GetUserDefaultLocaleName(name, LOCALE_NAME_MAX_LENGTH);
if (size > 1) // including '\0'
{
ffStrbufSetNWS(result, (uint32_t)size - 1, name);
ffStrbufAppendS(result, ".UTF-8"); // set explicitly in `ffInitInstance`
}
else
ffStrbufSetS(result, setlocale(LC_ALL, NULL));
}
+11
View File
@@ -9,6 +9,8 @@ static uint64_t time1;
void ffPrepareNetIO(FFNetIOOptions* options)
{
if (options->detectTotal) return;
ffListInit(&ioCounters1, sizeof(FFNetIOResult));
ffNetIOGetIoCounters(&ioCounters1, options);
time1 = ffTimeGetNow();
@@ -17,6 +19,15 @@ void ffPrepareNetIO(FFNetIOOptions* options)
const char* ffDetectNetIO(FFlist* result, FFNetIOOptions* options)
{
const char* error = NULL;
if (options->detectTotal)
{
error = ffNetIOGetIoCounters(result, options);
if (error)
return error;
return NULL;
}
if (time1 == 0)
{
ffListInit(&ioCounters1, sizeof(FFNetIOResult));
+5 -5
View File
@@ -23,15 +23,15 @@ typedef struct OpenCLData
static const char* openCLHandleData(OpenCLData* data, FFOpenCLResult* result)
{
cl_platform_id platformID;
cl_uint numPlatforms;
cl_platform_id platformID = NULL;
cl_uint numPlatforms = 0;
data->ffclGetPlatformIDs(1, &platformID, &numPlatforms);
if(numPlatforms == 0)
return "clGetPlatformIDs returned 0 platforms";
cl_device_id deviceID;
cl_uint numDevices;
cl_device_id deviceID = NULL;
cl_uint numDevices = 0;
data->ffclGetDeviceIDs(platformID, CL_DEVICE_TYPE_GPU, 1, &deviceID, &numDevices);
if(numDevices == 0)
@@ -40,7 +40,7 @@ static const char* openCLHandleData(OpenCLData* data, FFOpenCLResult* result)
if(numDevices == 0)
return "clGetDeviceIDs returned 0 devices";
char version[64];
char version[64] = "";
data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VERSION, sizeof(version), version, NULL);
if(!ffStrSet(version))
return "clGetDeviceInfo returned NULL or empty string";
+11 -9
View File
@@ -99,14 +99,16 @@ static uint32_t getNixPackages(FFstrbuf* baseDir, const char* dirname)
return num_elements;
}
void ffDetectPackagesImpl(FFPackagesResult* result, FF_MAYBE_UNUSED FFPackagesOptions* options)
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
getBrewPackages(result);
result->macports = getMacPortsPackages();
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(FASTFETCH_TARGET_DIR_ROOT);
result->nixDefault += getNixPackages(&baseDir, "/nix/var/nix/profiles/default");
result->nixSystem += getNixPackages(&baseDir, "/run/current-system");
ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
result->nixUser = getNixPackages(&baseDir, "/.nix-profile");
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT)) getBrewPackages(result);
if (!(options->disabled & FF_PACKAGES_FLAG_MACPORTS_BIT)) result->macports = getMacPortsPackages();
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
{
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateS(FASTFETCH_TARGET_DIR_ROOT);
result->nixDefault += getNixPackages(&baseDir, "/nix/var/nix/profiles/default");
result->nixSystem += getNixPackages(&baseDir, "/run/current-system");
ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
result->nixUser = getNixPackages(&baseDir, "/.nix-profile");
}
}
+2 -1
View File
@@ -4,5 +4,6 @@
void ffDetectPackagesImpl(FFPackagesResult* result, FF_MAYBE_UNUSED FFPackagesOptions* options)
{
result->pkg = (uint32_t) ffSettingsGetSQLite3Int(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg/local.sqlite", "SELECT count(*) FROM packages");
if (!(options->disabled & FF_PACKAGES_FLAG_PKG_BIT))
result->pkg = (uint32_t) ffSettingsGetSQLite3Int(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg/local.sqlite", "SELECT count(*) FROM packages");
}
+44 -34
View File
@@ -253,44 +253,53 @@ static uint32_t getRpmFromLibrpm(void)
#endif //FF_HAVE_RPM
static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts)
static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options)
{
packageCounts->apk += getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q");
packageCounts->dpkg += getNumStrings(baseDir, "/var/lib/dpkg/status", "Status: install ok installed");
packageCounts->emerge += countFilesRecursive(baseDir, "/var/db/pkg", "SIZE");
packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", DT_DIR);
packageCounts->flatpakSystem += getFlatpak(baseDir, "/var/lib/flatpak");
packageCounts->nixDefault += getNixPackages(baseDir, "/nix/var/nix/profiles/default");
packageCounts->nixSystem += getNixPackages(baseDir, "/run/current-system");
packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", DT_DIR);
packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", DT_REG);
packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages");
packageCounts->snap += getSnap(baseDir);
packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
packageCounts->brewCask += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Caskroom", DT_DIR);
packageCounts->brew += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Cellar", DT_DIR);
packageCounts->paludis += countFilesRecursive(baseDir, "/var/db/paludis/repositories", "environment.bz2");
packageCounts->opkg += getNumStrings(baseDir, "/usr/lib/opkg/status", "Package:"); // openwrt
if (!(options->disabled & FF_PACKAGES_FLAG_APK_BIT)) packageCounts->apk += getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q");
if (!(options->disabled & FF_PACKAGES_FLAG_DPKG_BIT)) packageCounts->dpkg += getNumStrings(baseDir, "/var/lib/dpkg/status", "Status: install ok installed");
if (!(options->disabled & FF_PACKAGES_FLAG_EMERGE_BIT)) packageCounts->emerge += countFilesRecursive(baseDir, "/var/db/pkg", "SIZE");
if (!(options->disabled & FF_PACKAGES_FLAG_EOPKG_BIT)) packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", DT_DIR);
if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT)) packageCounts->flatpakSystem += getFlatpak(baseDir, "/var/lib/flatpak");
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
{
packageCounts->nixDefault += getNixPackages(baseDir, "/nix/var/nix/profiles/default");
packageCounts->nixSystem += getNixPackages(baseDir, "/run/current-system");
}
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", DT_DIR);
if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", DT_REG);
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages");
if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir);
if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
{
packageCounts->brewCask += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Caskroom", DT_DIR);
packageCounts->brew += getNumElements(baseDir, "/home/linuxbrew/.linuxbrew/Cellar", DT_DIR);
}
if (!(options->disabled & FF_PACKAGES_FLAG_PALUDIS_BIT)) packageCounts->paludis += countFilesRecursive(baseDir, "/var/db/paludis/repositories", "environment.bz2");
if (!(options->disabled & FF_PACKAGES_FLAG_OPKG_BIT)) packageCounts->opkg += getNumStrings(baseDir, "/usr/lib/opkg/status", "Package:"); // openwrt
}
static void getPackageCountsRegular(FFstrbuf* baseDir, FFPackagesResult* packageCounts)
static void getPackageCountsRegular(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options)
{
getPackageCounts(baseDir, packageCounts);
getPackageCounts(baseDir, packageCounts, options);
uint32_t baseDirLength = baseDir->length;
ffStrbufAppendS(baseDir, FASTFETCH_TARGET_DIR_ETC "/pacman-mirrors.conf");
if(ffParsePropFile(baseDir->chars, "Branch =", &packageCounts->pacmanBranch) && packageCounts->pacmanBranch.length == 0)
ffStrbufAppendS(&packageCounts->pacmanBranch, "stable");
ffStrbufSubstrBefore(baseDir, baseDirLength);
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT))
{
uint32_t baseDirLength = baseDir->length;
ffStrbufAppendS(baseDir, FASTFETCH_TARGET_DIR_ETC "/pacman-mirrors.conf");
if(ffParsePropFile(baseDir->chars, "Branch =", &packageCounts->pacmanBranch) && packageCounts->pacmanBranch.length == 0)
ffStrbufAppendS(&packageCounts->pacmanBranch, "stable");
ffStrbufSubstrBefore(baseDir, baseDirLength);
}
}
static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* packageCounts)
static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options)
{
uint32_t baseDirLength = baseDir->length;
ffStrbufAppendS(baseDir, "/bedrock/strata");
DIR* dir = opendir(baseDir->chars);
FF_AUTO_CLOSE_DIR DIR* dir = opendir(baseDir->chars);
if(dir == NULL)
{
ffStrbufSubstrBefore(baseDir, baseDirLength);
@@ -309,33 +318,34 @@ static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* package
continue;
ffStrbufAppendS(baseDir, entry->d_name);
getPackageCounts(baseDir, packageCounts);
getPackageCounts(baseDir, packageCounts, options);
ffStrbufSubstrBefore(baseDir, baseDirLength2);
}
closedir(dir);
ffStrbufSubstrBefore(baseDir, baseDirLength);
}
void ffDetectPackagesImpl(FFPackagesResult* result, FF_MAYBE_UNUSED FFPackagesOptions* options)
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(512);
ffStrbufAppendS(&baseDir, FASTFETCH_TARGET_DIR_ROOT);
if(ffStrbufIgnCaseEqualS(&ffDetectOS()->id, "bedrock"))
getPackageCountsBedrock(&baseDir, result);
getPackageCountsBedrock(&baseDir, result, options);
else
getPackageCountsRegular(&baseDir, result);
getPackageCountsRegular(&baseDir, result, options);
// If SQL failed, we can still try with librpm.
// This is needed on openSUSE, which seems to use a proprietary database file
// This method doesn't work on bedrock, so we do it here.
#ifdef FF_HAVE_RPM
if(result->rpm == 0)
if(!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT) && result->rpm == 0)
result->rpm = getRpmFromLibrpm();
#endif
ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
result->nixUser = getNixPackages(&baseDir, "/.nix-profile");
result->flatpakUser = getFlatpak(&baseDir, "/.local/share/flatpak");
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
result->nixUser = getNixPackages(&baseDir, "/.nix-profile");
if (!(options->disabled & FF_PACKAGES_FLAG_FLATPAK_BIT))
result->flatpakUser = getFlatpak(&baseDir, "/.local/share/flatpak");
}
+4 -5
View File
@@ -107,9 +107,8 @@ static void detectWinget(FFPackagesResult* result)
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
{
detectScoop(result);
detectChoco(result);
detectPacman(result);
if (options->winget)
detectWinget(result);
if (!(options->disabled & FF_PACKAGES_FLAG_SCOOP_BIT)) detectScoop(result);
if (!(options->disabled & FF_PACKAGES_FLAG_CHOCO_BIT)) detectChoco(result);
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) detectPacman(result);
if (!(options->disabled & FF_PACKAGES_FLAG_WINGET_BIT)) detectWinget(result);
}
@@ -13,5 +13,3 @@ typedef struct FFPowerAdapterResult
} FFPowerAdapterResult;
const char* ffDetectPowerAdapter(FFlist* results);
#define FF_POWERADAPTER_NOT_CONNECTED -1
+22 -12
View File
@@ -8,22 +8,32 @@
const char* ffDetectPowerAdapter(FFlist* results)
{
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef details = IOPSCopyExternalPowerAdapterDetails();
FFPowerAdapterResult* adapter = ffListAdd(results);
ffStrbufInit(&adapter->name);
ffStrbufInit(&adapter->description);
ffStrbufInit(&adapter->manufacturer);
ffStrbufInit(&adapter->modelName);
ffStrbufInit(&adapter->serial);
adapter->watts = FF_POWERADAPTER_NOT_CONNECTED;
if (details)
if (details && CFDictionaryContainsKey(details, CFSTR(kIOPSPowerAdapterWattsKey)))
{
FFPowerAdapterResult* adapter = ffListAdd(results);
ffStrbufInit(&adapter->name);
ffStrbufInit(&adapter->description);
ffStrbufInit(&adapter->manufacturer);
ffStrbufInit(&adapter->modelName);
ffStrbufInit(&adapter->serial);
adapter->watts = 0;
ffCfDictGetString(details, CFSTR(kIOPSNameKey), &adapter->name);
ffCfDictGetString(details, CFSTR("Model"), &adapter->modelName);
if (ffCfDictGetString(details, CFSTR("Model"), &adapter->modelName) != NULL)
{
int adapterId;
if (ffCfDictGetInt(details, CFSTR(kIOPSPowerAdapterIDKey), &adapterId) == 0)
ffStrbufSetF(&adapter->modelName, "%d", adapterId);
}
ffCfDictGetString(details, CFSTR("Manufacturer"), &adapter->manufacturer);
ffCfDictGetString(details, CFSTR("Description"), &adapter->description);
ffCfDictGetString(details, CFSTR("SerialString"), &adapter->serial);
if (ffCfDictGetString(details, CFSTR("SerialString"), &adapter->serial) != NULL)
{
int serialNumber;
if (ffCfDictGetInt(details, CFSTR(kIOPSPowerAdapterSerialNumberKey), &serialNumber) == 0)
ffStrbufSetF(&adapter->serial, "%X", serialNumber);
}
ffCfDictGetInt(details, CFSTR(kIOPSPowerAdapterWattsKey), &adapter->watts);
}
+12 -19
View File
@@ -28,6 +28,14 @@ static void parsePowerAdapter(FFstrbuf* dir, FF_MAYBE_UNUSED const char* id, FFl
if(ffStrbufIgnCaseEqualS(&tmpBuffer, "Device"))
return;
ffStrbufAppendS(dir, "/online");
char online = '1';
ffReadFileData(dir->chars, sizeof(online), &online);
ffStrbufSubstrBefore(dir, dirLength);
if (online == '0')
return;
//input_power_limit must exist and be not empty
ffStrbufAppendS(dir, "/input_power_limit");
bool available = ffReadFileBuffer(dir->chars, &tmpBuffer);
@@ -35,24 +43,14 @@ static void parsePowerAdapter(FFstrbuf* dir, FF_MAYBE_UNUSED const char* id, FFl
if (!available)
return;
FFPowerAdapterResult* result = ffListAdd(results);
ffStrbufInit(&result->name);
ffStrbufInit(&result->description);
ffStrbufAppendS(dir, "/online");
char online = '1';
ffReadFileData(dir->chars, sizeof(online), &online);
ffStrbufSubstrBefore(dir, dirLength);
if (online == '0')
result->watts = FF_POWERADAPTER_NOT_CONNECTED;
else
result->watts = (int) (ffStrbufToDouble(&tmpBuffer) / 1e6 + 0.5);
//At this point, we have a battery. Try to get as much values as possible.
result->watts = (int) (ffStrbufToDouble(&tmpBuffer) / 1e6 + 0.5);
ffStrbufInit(&result->manufacturer);
ffStrbufInit(&result->modelName);
ffStrbufInit(&result->serial);
ffStrbufAppendS(dir, "/manufacturer");
if (ffReadFileBuffer(dir->chars, &result->manufacturer))
ffStrbufTrimRightSpace(&result->manufacturer);
@@ -60,13 +58,11 @@ static void parsePowerAdapter(FFstrbuf* dir, FF_MAYBE_UNUSED const char* id, FFl
ffStrbufSetStatic(&result->manufacturer, "Apple Inc.");
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->modelName);
ffStrbufAppendS(dir, "/model_name");
if (ffReadFileBuffer(dir->chars, &result->modelName))
ffStrbufTrimRightSpace(&result->modelName);
ffStrbufSubstrBefore(dir, dirLength);
ffStrbufInit(&result->serial);
ffStrbufAppendS(dir, "/serial_number");
if (ffReadFileBuffer(dir->chars, &result->serial))
ffStrbufTrimRightSpace(&result->serial);
@@ -95,8 +91,5 @@ const char* ffDetectPowerAdapter(FFlist* results)
ffStrbufSubstrBefore(&baseDir, baseDirLength);
}
if(results->length == 0)
return "\"/sys/class/power_supply/\" doesn't contain any power adapter folder";
return NULL;
}
+6 -2
View File
@@ -6,13 +6,17 @@
#include <sys/user.h>
#endif
#ifndef KERN_PROC_PROC
#define KERN_PROC_PROC KERN_PROC_ALL // Apple
#endif
const char* ffDetectProcesses(uint32_t* result)
{
int request[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
int request[] = {CTL_KERN, KERN_PROC, KERN_PROC_PROC};
size_t length;
if(sysctl(request, sizeof(request) / sizeof(*request), NULL, &length, NULL, 0) != 0)
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}) failed";
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}) failed";
*result = (uint32_t)(length / sizeof(struct kinfo_proc));
return NULL;
+2 -2
View File
@@ -17,8 +17,8 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
IMMDeviceEnumerator* FF_AUTO_RELEASE_COM_OBJECT pEnum = NULL;
if (FAILED(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void **)&pEnum)))
return "CoCreateInstance(__uuidof(MMDeviceEnumerator)) failed";
if (FAILED(CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&pEnum)))
return "CoCreateInstance(CLSID_MMDeviceEnumerator) failed";
LPWSTR mainDeviceId = NULL;
+11 -1
View File
@@ -170,7 +170,17 @@ static void detectFromWindowsTeriminal(const FFstrbuf* terminalExe, FFTerminalFo
if(terminalExe && terminalExe->length > 0 && !ffStrbufEqualS(terminalExe, "Windows Terminal"))
{
char jsonPath[MAX_PATH + 1];
if(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, jsonPath)))
strncpy(jsonPath, terminalExe->chars, ffStrbufLastIndexC(terminalExe, '\\') + 1);
char* pathEnd = jsonPath + strlen(jsonPath);
strncpy(pathEnd, ".portable", sizeof(jsonPath) - (size_t) (pathEnd - jsonPath) - 1);
if(ffPathExists(jsonPath, FF_PATHTYPE_FILE))
{
strncpy(pathEnd, "settings\\settings.json", sizeof(jsonPath) - (size_t) (pathEnd - jsonPath) - 1);
if(!ffAppendFileBuffer(jsonPath, &json))
error = "Error reading Windows Terminal portable settings JSON file";
}
else if(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, jsonPath)))
{
size_t remaining = sizeof(jsonPath) - strlen(jsonPath) - 1;
if(ffStrbufContainIgnCaseS(terminalExe, "_8wekyb3d8bbwe\\"))
@@ -315,7 +315,7 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo
detectFromConfigFile("lxterminal/lxterminal.conf", "fontname =", terminalFont);
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "tilix"))
detectFromGSettings("/com/gexperts/Tilix/profiles/", "com.gexperts.Tilix.ProfilesList", "com.gexperts.Tilix.Profile", "default", terminalFont);
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "gnome-terminal-"))
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "gnome-terminal"))
detectFromGSettings("/org/gnome/terminal/legacy/profiles:/:", "org.gnome.Terminal.ProfilesList", "org.gnome.Terminal.Legacy.Profile", "default", terminalFont);
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "kgx"))
detectKgx(terminalFont);
+50 -7
View File
@@ -168,6 +168,23 @@ static bool getShellVersionAsh(FFstrbuf* exe, FFstrbuf* version)
return true;
}
static bool getShellVersionXonsh(FFstrbuf* exe, FFstrbuf* version)
{
ffStrbufSetS(version, getenv("XONSH_VERSION"));
if (version->length) return true;
if(ffProcessAppendStdErr(version, (char* const[]) {
exe->chars,
"--version",
NULL
}) != NULL)
return false;
// xonsh/0.14.1
ffStrbufSubstrAfterFirstC(version, '/');
return true;
}
#ifdef _WIN32
static bool getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version)
{
@@ -228,11 +245,8 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
return getExeVersionRaw(exe, version);
if(strcasecmp(exeName, "ash") == 0)
return getShellVersionAsh(exe, version);
if(strcasecmp(exeName, "python") == 0 && getenv("XONSH_VERSION"))
{
ffStrbufSetS(version, getenv("XONSH_VERSION"));
return true;
}
if(strcasecmp(exeName, "xonsh") == 0)
return getShellVersionXonsh(exe, version);
#ifdef _WIN32
if(strcasecmp(exeName, "powershell") == 0 || strcasecmp(exeName, "powershell_ise") == 0)
@@ -267,7 +281,7 @@ FF_MAYBE_UNUSED static bool getTerminalVersionGnome(FFstrbuf* version)
FF_MAYBE_UNUSED static bool getTerminalVersionKgx(FFstrbuf* version)
{
if(ffProcessAppendStdOut(version, (char* const[]){
"gnome-terminal",
"kgx",
"--version",
NULL
})) return false;
@@ -342,6 +356,20 @@ FF_MAYBE_UNUSED static bool getTerminalVersionXterm(FFstrbuf* exe, FFstrbuf* ver
return version->length > 0;
}
FF_MAYBE_UNUSED static bool getTerminalVersionBlackbox(FFstrbuf* exe, FFstrbuf* version)
{
if(ffProcessAppendStdOut(version, (char* const[]){
exe->chars,
"--version",
NULL
})) return false;
//BlackBox version 0.14.0 (flatpak)
ffStrbufSubstrAfterFirstS(version, "version ");
ffStrbufSubstrBeforeFirstC(version, ' ');
return version->length > 0;
}
FF_MAYBE_UNUSED static bool getTerminalVersionUrxvt(FF_MAYBE_UNUSED FFstrbuf* exe, FFstrbuf* version)
{
if(ffProcessAppendStdErr(version, (char* const[]){
@@ -386,6 +414,15 @@ static bool getTerminalVersionContour(FFstrbuf* exe, FFstrbuf* version)
return version->length > 0;
}
static bool getTerminalVersionScreen(FFstrbuf* exe, FFstrbuf* version)
{
if(!getExeVersionRaw(exe, version)) return false;
// Screen version 4.09.01 (GNU) 20-Aug-23
ffStrbufSubstrAfter(version, strlen("Screen version ") - 1);
ffStrbufSubstrBeforeFirstC(version, ' ');
return version->length > 0;
}
#ifdef _WIN32
static bool getTerminalVersionWindowsTerminal(FFstrbuf* exe, FFstrbuf* version)
@@ -426,7 +463,7 @@ bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe
#if defined(__linux__) || defined(__FreeBSD__)
if(ffStrbufStartsWithIgnCaseS(processName, "gnome-terminal-"))
if(ffStrbufStartsWithIgnCaseS(processName, "gnome-terminal"))
return getTerminalVersionGnome(version);
if(ffStrbufIgnCaseEqualS(processName, "konsole"))
@@ -459,6 +496,9 @@ bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe
if(ffStrbufIgnCaseEqualS(processName, "xterm"))
return getTerminalVersionXterm(exe, version);
if(ffStrbufIgnCaseEqualS(processName, "blackbox"))
return getTerminalVersionBlackbox(exe, version);
if(ffStrbufIgnCaseEqualS(processName, "st"))
return getTerminalVersionSt(exe, version);
@@ -497,6 +537,9 @@ bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe
if(ffStrbufStartsWithIgnCaseS(processName, "contour"))
return getTerminalVersionContour(exe, version);
if(ffStrbufStartsWithIgnCaseS(processName, "screen"))
return getTerminalVersionScreen(exe, version);
const char* termProgramVersion = getenv("TERM_PROGRAM_VERSION");
if(termProgramVersion)
{
+4 -1
View File
@@ -5,12 +5,14 @@
typedef struct FFShellResult
{
FFstrbuf processName;
FFstrbuf exe;
FFstrbuf exe; //Actually arg0 in *nix
const char* exeName; //pointer to a char in exe
FFstrbuf exePath; //Full real path to executable file
FFstrbuf prettyName;
FFstrbuf version;
uint32_t pid;
uint32_t ppid;
int32_t tty;
} FFShellResult;
typedef struct FFTerminalResult
@@ -19,6 +21,7 @@ typedef struct FFTerminalResult
FFstrbuf exe;
FFstrbuf prettyName;
const char* exeName; //pointer to a char in exe
FFstrbuf exePath; //Full real path to executable file
FFstrbuf version;
uint32_t pid;
uint32_t ppid;
+204 -58
View File
@@ -4,14 +4,13 @@
#include "common/processing.h"
#include "common/thread.h"
#include "util/stringUtils.h"
#include "util/mallocHelper.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef __APPLE__
#include <libproc.h>
#elif defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__APPLE__)
#include <sys/types.h>
#include <sys/user.h>
#include <sys/sysctl.h>
@@ -25,38 +24,94 @@ static void setExeName(FFstrbuf* exe, const char** exeName)
*exeName = exe->chars + lastSlashIndex + 1;
}
static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName)
static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath)
{
assert(processName->length > 0);
ffStrbufClear(exe);
#ifdef __linux__
char cmdlineFilePath[64];
snprintf(cmdlineFilePath, sizeof(cmdlineFilePath), "/proc/%d/cmdline", (int)pid);
char filePath[64];
snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int)pid);
if(ffAppendFileBuffer(cmdlineFilePath, exe))
if(ffAppendFileBuffer(filePath, exe))
{
ffStrbufTrimRightSpace(exe);
ffStrbufSubstrBeforeFirstC(exe, '\0'); //Trim the arguments
ffStrbufTrimLeft(exe, '-'); //Happens in TTY
ffStrbufRecalculateLength(exe); //Trim the arguments
ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash
}
snprintf(filePath, sizeof(filePath), "/proc/%d/exe", (int)pid);
ffStrbufEnsureFixedLengthFree(exePath, PATH_MAX);
ssize_t length = readlink(filePath, exePath->chars, exePath->allocated - 1);
if (length > 0) // doesn't contain trailing NUL
{
exePath->chars[length + 1] = '\0';
exePath->length = (uint32_t) length;
}
#elif defined(__APPLE__)
int length = proc_pidpath((int)pid, exe->chars, exe->allocated);
if(length > 0)
exe->length = (uint32_t)length;
size_t len = 0;
int mibs[] = { CTL_KERN, KERN_PROCARGS2, pid };
if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), NULL, &len, NULL, 0) == 0)
{
FF_AUTO_FREE char* const procArgs2 = malloc(len);
if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), procArgs2, &len, NULL, 0) == 0)
{
// https://gist.github.com/nonowarn/770696#file-getargv-c-L46
uint32_t argc = *(uint32_t*) procArgs2;
const char* realExePath = procArgs2 + sizeof(argc);
const char* arg0 = memchr(realExePath, '\0', len - (size_t) (realExePath - procArgs2));
ffStrbufSetNS(exePath, (uint32_t) (arg0 - realExePath), realExePath);
do arg0++; while (*arg0 == '\0');
assert(arg0 < procArgs2 + len);
if (*arg0 == '-') arg0++; // Login shells
ffStrbufSetS(exe, arg0);
}
}
#elif defined(__FreeBSD__)
size_t size = exe->allocated;
if(!sysctl(
size_t size = ARG_MAX;
FF_AUTO_FREE char* args = malloc(size);
static_assert(ARG_MAX > PATH_MAX, "");
if(sysctl(
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}, 4,
exe->chars, &size,
args, &size,
NULL, 0
))
exe->length = (uint32_t)size - 1;
) == 0)
ffStrbufSetNS(exePath, (uint32_t) (size - 1), args);
size = ARG_MAX;
if(sysctl(
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_ARGS, pid}, 4,
args, &size,
NULL, 0
) == 0)
{
char* arg0 = args;
size_t arg0Len = strlen(args);
if (size > arg0Len + 1)
{
char* p = (char*) memrchr(args, '/', arg0Len);
if (p)
{
p++;
if (ffStrStartsWith(p, "python")) // /usr/local/bin/python3.9 /home/carter/.local/bin/xonsh
{
arg0 += arg0Len + 1;
}
}
}
if (arg0[0] == '-') arg0++;
ffStrbufSetS(exe, arg0);
}
#endif
@@ -66,8 +121,11 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex
setExeName(exe, exeName);
}
static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid)
static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid, int32_t* tty)
{
if (pid <= 0)
return "Invalid pid";
#ifdef __linux__
char statFilePath[64];
@@ -79,21 +137,43 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid)
buf[nRead] = '\0';
*ppid = 0;
static_assert(sizeof(*ppid) == sizeof(int), "");
int tty_;
if(
sscanf(buf, "%*s (%255[^)]) %*c %d", name, ppid) != 2 || //stat (comm) state ppid
sscanf(buf, "%*s (%255[^)]) %*c %d %*d %*d %d", name, ppid, &tty_) < 2 || //stat (comm) state ppid pgrp session tty
!ffStrSet(name) ||
*ppid == 0
)
return "sscanf(stat) failed";
if (tty)
{
if ((tty_ >> 8) == 0x88)
*tty = tty_ & 0xFF;
else
*tty = -1;
}
#elif defined(__APPLE__)
struct proc_bsdshortinfo proc;
if(proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 0, &proc, PROC_PIDT_SHORTBSDINFO_SIZE) <= 0)
return "proc_pidinfo(pid) failed";
struct kinfo_proc proc;
size_t size = sizeof(proc);
if(sysctl(
(int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4,
&proc, &size,
NULL, 0
))
return "sysctl(KERN_PROC_PID) failed";
*ppid = (pid_t)proc.pbsi_ppid;
strncpy(name, proc.pbsi_comm, 16); //trancated to 16 chars
*ppid = (pid_t)proc.kp_eproc.e_ppid;
strcpy(name, proc.kp_proc.p_comm); //trancated to 16 chars
if (tty)
{
*tty = ((proc.kp_eproc.e_tdev >> 24) & 0xFF) == 0x10
? proc.kp_eproc.e_tdev & 0xFFFFFF
: -1;
}
#elif defined(__FreeBSD__)
@@ -107,7 +187,20 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid)
return "sysctl(KERN_PROC_PID) failed";
*ppid = (pid_t)proc.ki_ppid;
strncpy(name, proc.ki_comm, COMMLEN);
strcpy(name, proc.ki_comm);
if (tty)
{
if (proc.ki_tdev != NODEV && proc.ki_flag & P_CONTROLT)
{
const char* ttyName = devname(proc.ki_tdev, S_IFCHR);
if (ffStrStartsWith(ttyName, "pts/"))
*tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10);
else
*tty = -1;
}
else
*tty = -1;
}
#else
@@ -124,11 +217,13 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid)
name[0] = '\0';
pid_t ppid = 0;
int32_t tty = -1;
while (getProcessNameAndPpid(pid, name, &ppid) == NULL)
while (getProcessNameAndPpid(pid, name, &ppid, &tty) == NULL)
{
//Common programs that are between terminal and own process, but are not the shell
if(
// tty < 0 || //A shell should connect to a tty
ffStrEquals(name, "sh") || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell
ffStrEquals(name, "sudo") ||
ffStrEquals(name, "su") ||
@@ -152,8 +247,9 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid)
result->pid = (uint32_t) pid;
result->ppid = (uint32_t) ppid;
result->tty = tty;
ffStrbufSetS(&result->processName, name);
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName);
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
break;
}
return ppid;
@@ -166,10 +262,11 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
pid_t ppid = 0;
while (getProcessNameAndPpid(pid, name, &ppid) == NULL)
while (getProcessNameAndPpid(pid, name, &ppid, NULL) == NULL)
{
//Known shells
if (
ffStrEquals(name, "sh") ||
ffStrEquals(name, "ash") ||
ffStrEquals(name, "bash") ||
ffStrEquals(name, "zsh") ||
@@ -185,7 +282,13 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
ffStrEquals(name, "git-shell") ||
ffStrEquals(name, "elvish") ||
ffStrEquals(name, "oil.ovm") ||
(ffStrEquals(name, "python") && getenv("XONSH_VERSION"))
ffStrEquals(name, "xonsh") || // works in Linux but not in macOS because kernel returns `Python` in this case
ffStrEquals(name, "login") ||
ffStrEquals(name, "sshd") ||
#ifdef __linux__
ffStrStartsWith(name, "flatpak-") || // #707
#endif
ffStrEndsWith(name, ".sh")
)
{
pid = ppid;
@@ -196,19 +299,39 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
// https://github.com/fastfetch-cli/fastfetch/discussions/501
if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)"))
{
if (__builtin_expect(getProcessNameAndPpid(ppid, name, &ppid) != NULL, false))
if (__builtin_expect(getProcessNameAndPpid(ppid, name, &ppid, NULL) != NULL, false))
return 0;
}
#endif
result->pid = (uint32_t) pid;
result->ppid = (uint32_t) ppid;
ffStrbufSetS(&result->processName, name);
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName);
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
break;
}
return ppid;
}
static bool getTerminalInfoByPidEnv(FFTerminalResult* result, const char* pidEnv)
{
const char* envStr = getenv(pidEnv);
if (envStr == NULL)
return false;
pid_t pid = (pid_t) strtol(envStr, NULL, 10);
result->pid = (uint32_t) pid;
char name[256];
if (getProcessNameAndPpid(pid, name, (pid_t*) &result->ppid, NULL) == NULL)
{
ffStrbufSetS(&result->processName, name);
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName, &result->exePath);
return true;
}
return false;
}
static void getTerminalFromEnv(FFTerminalResult* result)
{
if(
@@ -231,58 +354,80 @@ static void getTerminalFromEnv(FFTerminalResult* result)
const char* term = NULL;
//SSH
if(getenv("SSH_CONNECTION") != NULL)
if(
getenv("SSH_TTY") != NULL
)
term = getenv("SSH_TTY");
else if(
getenv("KITTY_PID") != NULL ||
getenv("KITTY_INSTALLATION_DIR") != NULL
)
{
if (getTerminalInfoByPidEnv(result, "KITTY_PID"))
return;
term = "kitty";
}
#ifdef __linux__
#ifdef __linux__ // WSL
//Windows Terminal
if(!ffStrSet(term) && (
else if(
getenv("WT_SESSION") != NULL ||
getenv("WT_PROFILE_ID") != NULL
)) term = "Windows Terminal";
) term = "Windows Terminal";
//ConEmu
if(!ffStrSet(term) && (
else if(
getenv("ConEmuPID") != NULL
)) term = "ConEmu";
) term = "ConEmu";
#endif
//Alacritty
if(!ffStrSet(term) && (
else if(
getenv("ALACRITTY_SOCKET") != NULL ||
getenv("ALACRITTY_LOG") != NULL ||
getenv("ALACRITTY_WINDOW_ID") != NULL
)) term = "Alacritty";
) term = "Alacritty";
#ifdef __ANDROID__
//Termux
if(!ffStrSet(term) && (
else if(
getenv("TERMUX_VERSION") != NULL ||
getenv("TERMUX_MAIN_PACKAGE_FORMAT") != NULL
)) term = "com.termux";
)
{
if (getTerminalInfoByPidEnv(result, "TERMUX_APP__PID"))
return;
term = "com.termux";
}
#endif
#ifdef __linux__
#if defined(__linux__) || defined(__FreeBSD__)
//Konsole
if(!ffStrSet(term) && (
else if(
getenv("KONSOLE_VERSION") != NULL
)) term = "konsole";
) term = "konsole";
else if(
getenv("GNOME_TERMINAL_SCREEN") != NULL ||
getenv("GNOME_TERMINAL_SERVICE") != NULL
) term = "gnome-terminal";
#endif
//MacOS, mintty
if(!ffStrSet(term))
else if(getenv("TERM_PROGRAM") != NULL)
term = getenv("TERM_PROGRAM");
if(!ffStrSet(term))
else if(getenv("LC_TERMINAL") != NULL)
term = getenv("LC_TERMINAL");
//Normal Terminal
if(!ffStrSet(term))
else
{
term = getenv("TERM");
//TTY
if(!ffStrSet(term) || ffStrEquals(term, "linux"))
term = ttyname(STDIN_FILENO);
//TTY
if(!ffStrSet(term) || ffStrEquals(term, "linux"))
term = ttyname(STDIN_FILENO);
}
if(ffStrSet(term))
{
@@ -316,8 +461,6 @@ static void setShellInfoDetails(FFShellResult* result)
ffStrbufInitStatic(&result->prettyName, "PowerShell");
else if(ffStrbufEqualS(&result->processName, "nu"))
ffStrbufInitStatic(&result->prettyName, "nushell");
else if(ffStrbufEqualS(&result->processName, "python") && getenv("XONSH_VERSION"))
ffStrbufInitStatic(&result->prettyName, "xonsh");
else if(ffStrbufEqualS(&result->processName, "oil.ovm"))
ffStrbufInitStatic(&result->prettyName, "Oils");
else
@@ -343,6 +486,8 @@ static void setTerminalInfoDetails(FFTerminalResult* result)
ffStrbufInitStatic(&result->prettyName, "WezTerm");
else if(ffStrbufStartsWithS(&result->processName, "tmux:"))
ffStrbufInitStatic(&result->prettyName, "tmux");
else if(ffStrbufStartsWithS(&result->processName, "screen-"))
ffStrbufInitStatic(&result->prettyName, "screen");
#if defined(__ANDROID__)
@@ -351,7 +496,7 @@ static void setTerminalInfoDetails(FFTerminalResult* result)
#elif defined(__linux__) || defined(__FreeBSD__)
else if(ffStrbufStartsWithS(&result->processName, "gnome-terminal-"))
else if(ffStrbufStartsWithS(&result->processName, "gnome-terminal"))
ffStrbufInitStatic(&result->prettyName, "GNOME Terminal");
else if(ffStrbufStartsWithS(&result->processName, "kgx"))
ffStrbufInitStatic(&result->prettyName, "GNOME Console");
@@ -377,13 +522,10 @@ static void setTerminalInfoDetails(FFTerminalResult* result)
else
ffStrbufInitCopy(&result->prettyName, &result->processName);
ffStrbufInit(&result->version);
fftsGetTerminalVersion(&result->processName, &result->exe, &result->version);
}
#ifdef __APPLE__
#define FF_EXE_PATH_LEN PROC_PIDPATHINFO_MAXSIZE
#elif defined(MAXPATH)
#if defined(MAXPATH)
#define FF_EXE_PATH_LEN MAXPATH
#elif defined(PATH_MAX)
#define FF_EXE_PATH_LEN PATH_MAX
@@ -402,9 +544,11 @@ const FFShellResult* ffDetectShell()
ffStrbufInit(&result.processName);
ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN);
result.exeName = result.exe.chars;
ffStrbufInit(&result.exePath);
ffStrbufInit(&result.version);
result.pid = 0;
result.ppid = 0;
result.tty = -1;
pid_t ppid = getppid();
ppid = getShellInfo(&result, ppid);
@@ -425,6 +569,8 @@ const FFTerminalResult* ffDetectTerminal()
ffStrbufInit(&result.processName);
ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN);
result.exeName = result.exe.chars;
ffStrbufInit(&result.exePath);
ffStrbufInit(&result.version);
result.pid = 0;
result.ppid = 0;
@@ -39,15 +39,18 @@ static bool getProductVersion(const wchar_t* filePath, FFstrbuf* version)
return false;
}
static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName)
static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath, bool* gui)
{
HANDLE hProcess = pid == 0
FF_AUTO_CLOSE_FD HANDLE hProcess = pid == 0
? GetCurrentProcess()
: OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid);
if (gui)
*gui = GetGuiResources(hProcess, GR_GDIOBJECTS) > 0;
if(ppid)
{
PROCESS_BASIC_INFORMATION info;
PROCESS_BASIC_INFORMATION info = {};
ULONG size;
if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size)))
{
@@ -55,21 +58,20 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb
*ppid = (uint32_t)info.InheritedFromUniqueProcessId;
}
else
{
CloseHandle(hProcess);
return false;
}
}
if(exe)
{
DWORD bufSize = exe->allocated;
if(QueryFullProcessImageNameA(hProcess, 0, exe->chars, &bufSize))
exe->length = bufSize;
else
{
CloseHandle(hProcess);
return false;
// We use full path here
// Querying command line of remote processes in Windows requires either WMI or ReadProcessMemory
exe->length = bufSize;
if (exePath) ffStrbufSet(exePath, exe);
}
else
return false;
}
if(pname && exeName)
{
@@ -77,7 +79,6 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb
ffStrbufSetS(pname, *exeName);
}
CloseHandle(hProcess);
return true;
}
@@ -85,9 +86,9 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version);
static uint32_t getShellInfo(FFShellResult* result, uint32_t pid)
{
uint32_t ppid;
uint32_t ppid = 0;
while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName))
while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath, NULL))
{
ffStrbufSet(&result->prettyName, &result->processName);
if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe"))
@@ -103,7 +104,8 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid)
ffStrbufIgnCaseEqualS(&result->prettyName, "gdb") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "lldb") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "guake-wrapped") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || //scoop warps the real binaries with a "shim" exe
ffStrbufIgnCaseEqualS(&result->prettyName, "python") || // python on windows generates shim executables
ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || // scoop warps the real binaries with a "shim" exe
ffStrbufIgnCaseEqualS(&result->prettyName, "flashfetch") ||
ffStrbufContainIgnCaseS(&result->prettyName, "debug") ||
ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014
@@ -116,9 +118,6 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid)
continue;
}
ffStrbufClear(&result->version);
fftsGetShellVersion(&result->exe, result->prettyName.chars, &result->version);
result->pid = pid;
result->ppid = ppid;
@@ -187,7 +186,7 @@ static bool getTerminalFromEnv(FFTerminalResult* result)
//ConEmu
uint32_t pid = (uint32_t) strtoul(term, NULL, 10);
result->pid = pid;
if(getProcessInfo(pid, NULL, &result->processName, &result->exe, &result->exeName))
if(getProcessInfo(pid, NULL, &result->processName, &result->exe, &result->exeName, &result->exePath, NULL))
{
ffStrbufSet(&result->prettyName, &result->processName);
if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe"))
@@ -243,12 +242,8 @@ static bool detectDefaultTerminal(FFTerminalResult* result)
DWORD bufSize = 80;
if (RegGetValueW(HKEY_CURRENT_USER, L"Console\\%%Startup", L"DelegationTerminal", RRF_RT_REG_SZ, NULL, uuid, &bufSize) == ERROR_SUCCESS)
{
if(wcscmp(uuid, L"{00000000-0000-0000-0000-000000000000}") == 0)
{
// Let Windows decide
return false;
}
if(wcscmp(uuid, L"{B23D10C0-E52E-411E-9D5B-C09FDF709C7D}") == 0)
if(wcscmp(uuid, L"{00000000-0000-0000-0000-000000000000}") == 0 || // Let Windows decide
wcscmp(uuid, L"{B23D10C0-E52E-411E-9D5B-C09FDF709C7D}") == 0) // Conhost
{
goto conhost;
}
@@ -296,50 +291,39 @@ conhost:
static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid)
{
uint32_t ppid;
uint32_t ppid = 0;
bool hasGui;
while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName))
while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath, &hasGui))
{
ffStrbufSet(&result->prettyName, &result->processName);
if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe"))
ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4);
if(
ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "cmd") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "bash") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "zsh") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "fish") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "nu") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "powershell") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "wsl") || // running inside wsl
ffStrbufIgnCaseEqualS(&result->prettyName, "servercoreshell") || // ServerCore Shell Launcher
ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmuC") // wrapper process of ConEmu
) {
//We are nested shell
if(!hasGui)
{
//We are in nested shell
ffStrbufClear(&result->processName);
ffStrbufClear(&result->prettyName);
ffStrbufClear(&result->exe);
ffStrbufClear(&result->exePath);
result->exeName = "";
pid = ppid;
continue;
}
ffStrbufSet(&result->prettyName, &result->processName);
if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe"))
ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4);
if(ffStrbufIgnCaseEqualS(&result->prettyName, "sihost") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")
) {
// A CUI program created by Windows Explorer will spawn a conhost as its child.
// However the conhost process is just a placeholder;
// The true terminal can be Windows Terminal or others.
if (!getTerminalFromEnv(result) && !detectDefaultTerminal(result))
{
ffStrbufClear(&result->processName);
ffStrbufClear(&result->prettyName);
ffStrbufClear(&result->exe);
result->exeName = "";
return 0;
}
ffStrbufClear(&result->processName);
ffStrbufClear(&result->prettyName);
ffStrbufClear(&result->exe);
ffStrbufClear(&result->exePath);
result->exeName = "";
return 0;
}
else
{
@@ -380,19 +364,30 @@ const FFShellResult* ffDetectShell(void)
init = true;
ffStrbufInit(&result.processName);
ffStrbufInitA(&result.exe, 128);
ffStrbufInitA(&result.exe, MAX_PATH);
result.exeName = "";
ffStrbufInit(&result.exePath);
ffStrbufInit(&result.prettyName);
ffStrbufInit(&result.version);
result.pid = 0;
result.ppid = 0;
result.tty = -1;
uint32_t ppid;
if(!getProcessInfo(0, &ppid, NULL, NULL, NULL))
if(!getProcessInfo(0, &ppid, NULL, NULL, NULL, NULL, NULL))
return &result;
ppid = getShellInfo(&result, ppid);
setShellInfoDetails(&result);
if (result.processName.length > 0)
{
setShellInfoDetails(&result);
char tmp[MAX_PATH];
strcpy(tmp, result.exeName);
char* ext = strrchr(tmp, '.');
if (ext) *ext = '\0';
fftsGetShellVersion(&result.exe, tmp, &result.version);
}
return &result;
}
@@ -406,8 +401,9 @@ const FFTerminalResult* ffDetectTerminal(void)
init = true;
ffStrbufInit(&result.processName);
ffStrbufInitA(&result.exe, 128);
ffStrbufInitA(&result.exe, MAX_PATH);
result.exeName = "";
ffStrbufInit(&result.exePath);
ffStrbufInit(&result.prettyName);
ffStrbufInit(&result.version);
result.pid = 0;
@@ -419,10 +415,14 @@ const FFTerminalResult* ffDetectTerminal(void)
if(result.processName.length == 0)
getTerminalFromEnv(&result);
if(result.processName.length == 0)
detectDefaultTerminal(&result);
setTerminalInfoDetails(&result);
fftsGetTerminalVersion(&result.processName, &result.exe, &result.version);
if(result.processName.length > 0)
{
setTerminalInfoDetails(&result);
fftsGetTerminalVersion(&result.processName, &result.exe, &result.version);
}
return &result;
}
@@ -10,10 +10,10 @@ bool ffDetectTerminalSize(FFTerminalSizeResult* result)
ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
if (winsize.ws_row == 0 || winsize.ws_col == 0)
ffGetTerminalResponse("\033[18t", "\033[8;%hu;%hut", &winsize.ws_row, &winsize.ws_col);
ffGetTerminalResponse("\e[18t", "\e[8;%hu;%hut", &winsize.ws_row, &winsize.ws_col);
if (winsize.ws_ypixel == 0 || winsize.ws_xpixel == 0)
ffGetTerminalResponse("\033[14t", "\033[4;%hu;%hut", &winsize.ws_ypixel, &winsize.ws_xpixel);
ffGetTerminalResponse("\e[14t", "\e[4;%hu;%hut", &winsize.ws_ypixel, &winsize.ws_xpixel);
if (winsize.ws_row == 0 && winsize.ws_col == 0)
return false;
@@ -14,7 +14,7 @@ bool ffDetectTerminalSize(FFTerminalSizeResult* result)
}
else
{
ffGetTerminalResponse("\033[18t", "\033[8;%hu;%hut", &result->rows, &result->columns);
ffGetTerminalResponse("\e[18t", "\e[8;%hu;%hut", &result->rows, &result->columns);
}
}
@@ -0,0 +1,91 @@
#include "terminaltheme.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
#include <inttypes.h>
static bool detectByEscapeCode(FFTerminalThemeResult* result)
{
int command = 0;
if (ffGetTerminalResponse("\e]10;?\e\\", "\e]%d;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 "\e\\", &command, &result->fg.r, &result->fg.g, &result->fg.b) == NULL)
{
if (command != 10)
return false;
if (result->fg.r > 0x0100 || result->fg.g > 0x0100 || result->fg.b > 0x0100)
result->fg.r /= 0x0100, result->fg.g /= 0x0100, result->fg.b /= 0x0100;
}
else
return false;
if (ffGetTerminalResponse("\e]11;?\e\\", "\e]%d;rgb:%" SCNx16 "/%" SCNx16 "/%" SCNx16 "\e\\", &command, &result->bg.r, &result->bg.g, &result->bg.b) == NULL)
{
if (command != 11)
return false;
if (result->bg.r > 0x0100 || result->bg.g > 0x0100 || result->bg.b > 0x0100)
result->bg.r /= 0x0100, result->bg.g /= 0x0100, result->bg.b /= 0x0100;
}
else
return false;
return true;
}
static FFTerminalThemeColor fgbgToColor(int num)
{
// https://github.com/dalance/termbg/blob/13c478a433fa182e65c401d26a1e7792a7f7f453/src/lib.rs#L251
switch (num)
{
case 0: return (FFTerminalThemeColor){ 0, 0, 0, false}; // black
case 1: return (FFTerminalThemeColor){205, 0, 0, false}; // red
case 2: return (FFTerminalThemeColor){ 0, 205, 0, false}; // green
case 3: return (FFTerminalThemeColor){205, 205, 0, false}; // yellow
case 4: return (FFTerminalThemeColor){ 0, 0, 238, false}; // blue
case 5: return (FFTerminalThemeColor){205, 0, 205, false}; // magenta
case 6: return (FFTerminalThemeColor){ 0, 205, 205, false}; // cyan
case 7: return (FFTerminalThemeColor){229, 229, 229, false}; // white
case 8: return (FFTerminalThemeColor){127, 127, 127, false}; // bright black
case 9: return (FFTerminalThemeColor){255, 0, 0, false}; // bright red
case 10: return (FFTerminalThemeColor){ 0, 255, 0, false}; // bright green
case 11: return (FFTerminalThemeColor){255, 255, 0, false}; // bright yellow
case 12: return (FFTerminalThemeColor){ 92, 92, 255, false}; // bright blue
case 13: return (FFTerminalThemeColor){255, 0, 255, false}; // bright magenta
case 14: return (FFTerminalThemeColor){ 0, 255, 255, false}; // bright cyan
case 15: return (FFTerminalThemeColor){255, 255, 255, false}; // bright white
default: return (FFTerminalThemeColor){ 0, 0, 0, false}; // invalid
}
}
static bool detectByEnv(FFTerminalThemeResult* result)
{
const char* color = getenv("COLORFGBG"); // 7;0
if (!ffStrSet(color))
return false;
int f, g;
if (sscanf(color, "%d;%d", &f, &g) != 2)
return false;
result->fg = fgbgToColor(f);
result->bg = fgbgToColor(g);
return true;
}
static inline bool detectColor(FFTerminalThemeResult* result)
{
if (detectByEscapeCode(result))
return true;
return detectByEnv(result);
}
bool ffDetectTerminalTheme(FFTerminalThemeResult* result)
{
if (!detectColor(result)) return false;
result->fg.dark = result->fg.r * 299 + result->fg.g * 587 + result->fg.b * 114 < 128000;
result->bg.dark = result->bg.r * 299 + result->bg.g * 587 + result->bg.b * 114 < 128000;
return true;
}
@@ -0,0 +1,19 @@
#pragma once
#include "fastfetch.h"
typedef struct FFTerminalThemeColor
{
uint16_t r;
uint16_t g;
uint16_t b;
bool dark;
} FFTerminalThemeColor;
typedef struct FFTerminalThemeResult
{
FFTerminalThemeColor fg;
FFTerminalThemeColor bg;
} FFTerminalThemeResult;
bool ffDetectTerminalTheme(FFTerminalThemeResult* result);
+5 -1
View File
@@ -250,7 +250,11 @@ static const char* detectWifiWithIoctls(FFlist* result)
item->conn.txRate = 0.0/0.0;
ffStrbufSetF(&path, "/sys/class/net/%s/operstate", i->if_name);
if (!ffAppendFileBuffer(path.chars, &item->inf.status) || !ffStrbufEqualS(&item->inf.status, "up\n"))
if (!ffAppendFileBuffer(path.chars, &item->inf.status))
continue;
ffStrbufTrimRightSpace(&item->inf.status);
if (!ffStrbufEqualS(&item->inf.status, "up"))
continue;
FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+28 -6
View File
@@ -7,6 +7,7 @@
#include "common/jsonconfig.h"
#include "detection/version/version.h"
#include "util/stringUtils.h"
#include "util/mallocHelper.h"
#include "logo/logo.h"
#include "fastfetch_datatext.h"
@@ -221,7 +222,22 @@ static bool printSpecificCommandHelp(const char* command)
yyjson_val* remarkKey = yyjson_obj_get(flagObj, "remark");
if (remarkKey)
printf("%10s: %s\n", "Remark", yyjson_get_str(remarkKey));
{
if (yyjson_is_str(remarkKey))
printf("%10s: %s\n", "Remark", yyjson_get_str(remarkKey));
else if (yyjson_is_arr(remarkKey) && yyjson_arr_size(remarkKey) > 0)
{
yyjson_val* remarkStr;
size_t remarkIdx, remarkMax;
yyjson_arr_foreach(remarkKey, remarkIdx, remarkMax, remarkStr)
{
if (remarkIdx == 0)
printf("%10s: %s\n", "Remark", yyjson_get_str(remarkStr));
else
printf(" %s\n", yyjson_get_str(remarkStr));
}
}
}
return true;
}
@@ -299,7 +315,7 @@ static void listModules(bool pretty)
{
++count;
if (pretty)
printf("%d)%s%-13s: %s\n", count, count > 9 ? " " : " ", (*modules)->name, (*modules)->description);
printf("%d)%s%-14s: %s\n", count, count > 9 ? " " : " ", (*modules)->name, (*modules)->description);
else
printf("%s:%s\n", (*modules)->name, (*modules)->description);
}
@@ -482,10 +498,8 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val
if(isJsonConfig ? parseJsoncFile(value) : parseConfigFile(data, value))
return;
FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA(128);
if (ffPathExpandEnv(value, &absolutePath))
{
bool success = isJsonConfig ? parseJsoncFile(absolutePath.chars) : parseConfigFile(data, absolutePath.chars);
bool success = isJsonConfig ? parseJsoncFile(value) : parseConfigFile(data, value);
if(success)
return;
@@ -493,6 +507,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val
//Try to load as a relative path
FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA(128);
FF_LIST_FOR_EACH(FFstrbuf, path, instance.state.platform.dataDirs)
{
//We need to copy it, because if a config file loads a config file, the value of path must be unchanged
@@ -831,7 +846,14 @@ static void writeConfigFile(FFdata* data, const FFstrbuf* filename)
yyjson_mut_write_fp(stdout, doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES, NULL, NULL);
else
{
if (yyjson_mut_write_file(filename->chars, doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES, NULL, NULL))
size_t len;
FF_AUTO_FREE const char* str = yyjson_mut_write(doc, YYJSON_WRITE_INF_AND_NAN_AS_NULL | YYJSON_WRITE_PRETTY_TWO_SPACES, &len);
if (!str)
{
printf("Error: failed to generate config file\n");
exit(1);
}
if (ffWriteFileData(filename->chars, len, str))
printf("The generated config file has been written in `%s`\n", filename->chars);
else
{
+18
View File
@@ -0,0 +1,18 @@
$1_wwM $2_ww
$1MMM$2MMMM
$1MM
$3_ww##############yy_
$4wMMMMM$3###########$4MMMMm
$4,MMMMMMMMM$3######$4MMMMMMMM0_
$4wMMMMMMMMMMMMM$5MM$60MMMMMMMMMMm
$4,MMMMMMMMMMMMMMM$5MMMM$60MMMMMMMMM0,
$4wMMMMMMMMMMMMMMMM$5MMMMM0$6MMMMMMMMMMb
$4_MMMMMMMMMMMMMMMMMM$5MMMMMMM0$6MMMMMMMMM0,
$4_MMMMMMMMMMMMMMMMMMM$5MMMM$7M$5MMMW$6MMMMMMMMMM_
$4_MMMMMMMMMMMMMMMMMMMM$5MMMM$7M0$5MMMW$6MMMMMMMMMM_
$4~MMMMMMMMMMMMMMMMM$5MMMM$7M$5MMMW$6MMMMM00~
$4~MMMMMMMMMMMMM$5MMMWMMM$60MM$5MMM$6~
$4~MMMMMMMMMM$5MMMMM$60MMM~~
$4~MMMMMM$5MMM$60MM~
$4~MM$5M$6@~
$4M
+18
View File
@@ -0,0 +1,18 @@
,clll:.$2 .,::::::::::::'
$1:ooooooo$2 .;::::::::::::::
$1looooooo$2 ,:::::::::::::::'
$1looooooo$2 .::::::::::::::::
$1looooooo$2 ;:::::::::::::::.
$1looooooo$2 .::::::::::::::::
$1looooool$2;;;;,::::::::::::::::
$1looool$2::, .::::::::::::::
$1looooc$2:: ;::
$1looooc$2::;. .::;
$1loooool$2:::::::::::.
$1looooooo$2. .::::::'
$1looooooo$2 .::::::,;,..
$1looooooo$2 :::;' ';:;.
$1looooooo$2 ::: :::
$1cooooooo$2 .::' '::.
$1 .ooooc $2 ::, ,::
''''
+17
View File
@@ -0,0 +1,17 @@
:oooo, .','
.';;;.;oooooooolooooo'
coooooooooooooooooooooooolc'
.':oooooooooooo$2ll$1ooooooooooooool
.oooooooooooooooo$2ll$1oooooooooooo$2l$1ool
ooooooooooooooooo$2ll$1ooooooooooo$2ll$1oo'
oooo$2l$1oooooooooo$2lll$1ooooooooo$2lll$1oo
.ooooo$2lll$1ooooo$2lll$1ooooooooo$2lll$1ool
.ooooooo$2lll$1oo$2llll$1oooo$2lllll$1ooooo:
'oooooooo$2llllllllllll$1oooooooo'
.c,.oo$2lllll$1oooooooo.$2
'll;
'll.
lll
lll
;ll,
.l:
+17
View File
@@ -0,0 +1,17 @@
.;ooooooooooooooooooooooooooo.
,dddddddddddddddddddddddddddddd'$3;
$1 lddddddddddddddddddddddddddddd'$3;;;
$1ddddd$2,XXX.$1ddddd$2,XXX.$1dddd'$2,XXX.$3;;;;;
$1ddddd$2XX$1x$2XX$1ddddd$2XX$1x$2XX$1ddd'$2,XX$3x$2XX$3;;;;;
$1ddddd$2'XXX'$1ddddd$2'XXX'$1dd'$2XXXXXX'$3;;;;;
$1dddddd$2;X;$1ddddddd$2;X:$1d'$2XXX$3;;;;;;;;;;;
$1dddddd$2;X;$1ddddddd$2;X:$2XXX$3;;;;;;;;;;;;;
$1dddddd$2;X;$1dddddd'$2;XXX,,,,,,XXX.$3;;;;;
$1dddddd$2;X;$1dddd'$2XXXX$2XXXXXXXXX$3x$2XX$3;;;;;
$1dddddd$2;X;$1dd'$2XXX$3;;;;;;;;;;;$2XXX$3;;;;;;
$1dddddd$2;X;$1'$2XXX$3;;;;;;;;;;;;;;;;;;;;;;
$1dddddd$2;XXXXX,,,,,,,,,,,,,;XXX:$3;;;;;
$1dddddd$2:XXXXXXXXXXXXXXXXXXXX$3x$2XX$3;;;;;
$1ddddd'$3;;;;;;;;;;;;;;;;;;;$2'XXX'$3;;;;'
$1ddd'$3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$1o'$3;;;;;;;;;;;;;;;;;;;;;;;;;;;;'
+28
View File
@@ -0,0 +1,28 @@
'',,, ,,,d,
',, ,,'
', ,.
., '
. .
' .
.. oddddkdlc:;,.. ..
. ............lllc, .
. ....................: .
. . ....................
'. ..........'o........d0XX0.
....lllllllcOOOcllllll............cxlxc...;okkkx.
..................................';lc'...lo.
.'''''''''''''.....................,;,.......
',,,,,,,,,,,,,,,,''...............dkkkd......
',,,,,,,,,,,,,,,,,,,'............;okkkd;....
.,,,,,,,,,,,,,,,,,,,,,............;cll;.....
,,,,,,,,,,,,,,,,,,,,'....................:d,
,,,,,,,,,,,,,,,,,,,....................oxxx:
.,,,,,,,,,,,,,,,,,'..................oxxxxx. .
.,,,,,,,,,,,,,,'.......... ,oxxxxxxx .
.;,,,,,,,,,,,,'.. 'cxxxxxxxxx,
:dl:,'',,'.... .;lxxxxxxxxxd;
,codol:;'. ...,;cldxxxxxxxxxoc.
.:cxxxxxdlccccc:ccldxxxxxxxxxxxxxx::.
.'::dxxxxxxxxxxxxxxxxxxxxxxxd::'.
..,::cdxxxxxxxxxxxxxdc::,..
...,;:::::::;,...
+15
View File
@@ -0,0 +1,15 @@
. .:. . .:.
.^^.!.:::. .^!?J?^
.:^.^!!!~:~^. .7??77!~~^.
.~^.!??77?!.^~: ..:^^7JJJ7~~^.
.^~.^7???7~.~~. .7??????????!
.:^:^^~^^:!^ ^: .......^!:...
.!7~.::.!.::. ~BG~ :^ ^~:
:!!~ ~. ?BBBB! ^?J!. .!~.
:!. .JBY. .Y#BBBY?~!???J7. :^^.
.. :5#B#P~P#BBP?7?55J?J7:
^P#BBBBBBBB5?7J5555J!.....
!BBBBBBGBBGJ77::Y555J?77777^
?BBBBG5JJ5PJ?!: .?Y??????77?~.
.YBGPYJ??????Y?^^^^~7?????????7?!.
.^^:..::::::::.....:::::::::::..:.
+7
View File
@@ -0,0 +1,7 @@
// OOOOOOO SSSSSSS
// OO OO SS
zzzzzz // OO OO SS
zz // OO OO SSSS
zz // OO OO SS
zz // OO OO SS
zzzzzz // OOOOOOO SSSSSSS
+121 -1
View File
@@ -468,6 +468,23 @@ static const FFlogo A[] = {
.colorKeys = FF_COLOR_FG_YELLOW,
.colorTitle = FF_COLOR_FG_GREEN,
},
// Asahi2
{
.names = {"asahi2", "asahi-linux2"},
.lines = FASTFETCH_DATATEXT_LOGO_ASAHI2,
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.colors = {
FF_COLOR_FG_LIGHT_YELLOW,
FF_COLOR_FG_CYAN,
FF_COLOR_FG_RED,
FF_COLOR_FG_LIGHT_RED,
FF_COLOR_FG_WHITE,
FF_COLOR_FG_BLACK,
FF_COLOR_FG_LIGHT_CYAN,
},
.colorKeys = FF_COLOR_FG_YELLOW,
.colorTitle = FF_COLOR_FG_GREEN,
},
// Aster
{
.names = {"aster"},
@@ -974,7 +991,7 @@ static const FFlogo C[] = {
// ContainerLinux
{
.names = {"ContainerLinux", "Container Linux", "Container Linux by CoreOS"},
.lines = FASTFETCH_DATATEXT_LOGO_CONTAINER_LINUX,
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_COREOS,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_WHITE,
@@ -1445,6 +1462,22 @@ static const FFlogo F[] = {
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
},
// FedoraAsahiRemix
{
.names = {"fedora-asahi-remix"},
.lines = FASTFETCH_DATATEXT_LOGO_ASAHI,
.colors = {
FF_COLOR_FG_YELLOW,
FF_COLOR_FG_GREEN,
FF_COLOR_FG_RED,
"38", //cyan
FF_COLOR_FG_WHITE,
FF_COLOR_FG_CYAN,
FF_COLOR_FG_BLUE,
},
.colorKeys = FF_COLOR_FG_YELLOW,
.colorTitle = FF_COLOR_FG_GREEN,
},
// FedoraSmall
{
.names = {"Fedora_small", "fedora-linux-small"},
@@ -1468,6 +1501,68 @@ static const FFlogo F[] = {
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
},
// FedoraSilverblue
{
.names = {"Fedora_silverblue", "fedora-silverblue", "fedora-linux-silverblue", "fedora-linux_silverblue"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_SILVERBLUE,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_WHITE,
FF_COLOR_FG_CYAN,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
},
// FedoraKinoite
{
.names = {"Fedora_kinoite", "fedora-kinoite", "fedora-linux-kinoite", "fedora-linux_kinoite"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_KINOITE,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_WHITE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
},
// FedoraSericea
{
.names = {"Fedora_sericea", "fedora-sericea", "fedora-linux-sericea", "fedora-linux_sericea"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_SERICEA,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_WHITE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
},
// FedoraOnyx placeholder - Currently does not have a logo
//{
//.names = {"Fedora_onyx", "fedora-onyx", "fedora-linux-onyx", "fedora-linux_onyx"},
//.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
//.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_ONYX,
//.colors = {
//FF_COLOR_FG_BLUE,
//FF_COLOR_FG_WHITE,
//},
//.colorKeys = FF_COLOR_FG_BLUE,
//.colorTitle = FF_COLOR_FG_BLUE,
//},
// FedoraCoreOS
{
.names = {"Fedora_coreos", "fedora-coreos", "fedora-linux-coreos", "fedora-linux_coreos"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_COREOS,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_WHITE,
FF_COLOR_FG_RED,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_WHITE,
},
// FemboyOS
{
.names = {"FemboyOS"},
@@ -3127,6 +3222,14 @@ static const FFlogo P[] = {
FF_COLOR_FG_WHITE,
},
},
// PikaOS
{
.names = {"PikaOS"},
.lines = FASTFETCH_DATATEXT_LOGO_PIKAOS,
.colors = {
FF_COLOR_FG_YELLOW,
},
},
// Pisi
{
.names = {"Pisi"},
@@ -3820,6 +3923,15 @@ static const FFlogo T[] = {
FF_COLOR_FG_WHITE,
},
},
// Tatra
{
.names = {"Tatra"},
.lines = FASTFETCH_DATATEXT_LOGO_TATRA,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_GREEN,
},
},
// TeArch
{
.names = {"TeArch"},
@@ -4327,6 +4439,14 @@ static const FFlogo Z[] = {
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
},
// Z/OS
{
.names = {"z/OS", "zos"},
.lines = FASTFETCH_DATATEXT_LOGO_ZOS,
.colors = {
FF_COLOR_FG_BLUE,
},
},
// LAST
{},
};
+13 -9
View File
@@ -1,6 +1,6 @@
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "common/bar.h"
#include "common/percent.h"
#include "common/parsing.h"
#include "detection/battery/battery.h"
#include "modules/battery/battery.h"
@@ -24,12 +24,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin
{
if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT)
{
if(result->capacity <= 20)
ffAppendPercentBar(&str, result->capacity, 100, 100, 0);
else if(result->capacity <= 50)
ffAppendPercentBar(&str, result->capacity, 100, 0, 100);
else
ffAppendPercentBar(&str, result->capacity, 0, 100, 100);
ffPercentAppendBar(&str, result->capacity, options->percent);
}
if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT)
@@ -37,7 +32,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin
if(str.length > 0)
ffStrbufAppendC(&str, ' ');
ffAppendPercentNum(&str, result->capacity, 51, 21, str.length > 0);
ffPercentAppendNum(&str, result->capacity, options->percent, str.length > 0);
}
}
@@ -62,7 +57,7 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin
else
{
FF_STRBUF_AUTO_DESTROY capacityStr = ffStrbufCreate();
ffAppendPercentNum(&capacityStr, result->capacity, 51, 21, false);
ffPercentAppendNum(&capacityStr, result->capacity, options->percent, false);
ffPrintFormat(FF_BATTERY_MODULE_NAME, index, &options->moduleArgs, FF_BATTERY_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer},
{FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName},
@@ -127,6 +122,9 @@ bool ffParseBatteryCommandOptions(FFBatteryOptions* options, const char* key, co
}
#endif
if (ffPercentParseCommandOptions(key, subKey, value, &options->percent))
return true;
return false;
}
@@ -157,6 +155,9 @@ void ffParseBatteryJsonObject(FFBatteryOptions* options, yyjson_val* module)
continue;
}
if (ffPercentParseJsonObject(key, val, &options->percent))
continue;
ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
}
}
@@ -175,6 +176,8 @@ void ffGenerateBatteryJsonConfig(FFBatteryOptions* options, yyjson_mut_doc* doc,
if (options->temp != defaultOptions.temp)
yyjson_mut_obj_add_bool(doc, module, "temp", options->temp);
ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent);
}
void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -245,6 +248,7 @@ void ffInitBatteryOptions(FFBatteryOptions* options)
);
ffOptionInitModuleArg(&options->moduleArgs);
options->temp = false;
options->percent = (FFPercentConfig) { 50, 20 };
#ifdef _WIN32
options->useSetupApi = false;
+2
View File
@@ -3,6 +3,7 @@
// This file will be included in "fastfetch.h", do NOT put unnecessary things here
#include "common/option.h"
#include "common/percent.h"
typedef struct FFBatteryOptions
{
@@ -10,6 +11,7 @@ typedef struct FFBatteryOptions
FFModuleArgs moduleArgs;
bool temp;
FFPercentConfig percent;
#ifdef _WIN32
bool useSetupApi;
+26 -8
View File
@@ -1,3 +1,4 @@
#include "common/percent.h"
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "detection/bluetooth/bluetooth.h"
@@ -11,23 +12,31 @@ static void printDevice(FFBluetoothOptions* options, const FFBluetoothResult* de
if(options->moduleArgs.outputFormat.length == 0)
{
ffPrintLogoAndKey(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&device->name, stdout);
if(device->battery > 0)
printf(" (%d%%)", device->battery);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateCopy(&device->name);
if(!device->connected)
puts(" [disconnected]");
else
putchar('\n');
if (device->battery > 0 && device->battery <= 100)
{
if (buffer.length)
ffStrbufAppendC(&buffer, ' ');
ffPercentAppendNum(&buffer, device->battery, options->percent, buffer.length > 0);
}
if (!device->connected)
ffStrbufAppendS(&buffer, " [disconnected]");
ffStrbufPutTo(&buffer, stdout);
}
else
{
FF_STRBUF_AUTO_DESTROY percentageStr = ffStrbufCreate();
ffPercentAppendNum(&percentageStr, device->battery, options->percent, false);
ffPrintFormat(FF_BLUETOOTH_MODULE_NAME, index, &options->moduleArgs, FF_BLUETOOTH_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &device->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &device->address},
{FF_FORMAT_ARG_TYPE_STRBUF, &device->type},
{FF_FORMAT_ARG_TYPE_UINT8, &device->battery}
{FF_FORMAT_ARG_TYPE_STRBUF, &percentageStr}
});
}
}
@@ -86,6 +95,9 @@ bool ffParseBluetoothCommandOptions(FFBluetoothOptions* options, const char* key
return true;
}
if (ffPercentParseCommandOptions(key, subKey, value, &options->percent))
return true;
return false;
}
@@ -108,6 +120,9 @@ void ffParseBluetoothJsonObject(FFBluetoothOptions* options, yyjson_val* module)
continue;
}
if (ffPercentParseJsonObject(key, val, &options->percent))
continue;
ffPrintError(FF_BLUETOOTH_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
}
}
@@ -121,6 +136,8 @@ void ffGenerateBluetoothJsonConfig(FFBluetoothOptions* options, yyjson_mut_doc*
if (options->showDisconnected != defaultOptions.showDisconnected)
yyjson_mut_obj_add_bool(doc, module, "showDisconnected", options->showDisconnected);
ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent);
}
void ffGenerateBluetoothJsonResult(FF_MAYBE_UNUSED FFBluetoothOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -181,6 +198,7 @@ void ffInitBluetoothOptions(FFBluetoothOptions* options)
);
ffOptionInitModuleArg(&options->moduleArgs);
options->showDisconnected = false;
options->percent = (FFPercentConfig) { 50, 20 };
}
void ffDestroyBluetoothOptions(FFBluetoothOptions* options)
+2
View File
@@ -3,6 +3,7 @@
// This file will be included in "fastfetch.h", do NOT put unnecessary things here
#include "common/option.h"
#include "common/percent.h"
typedef struct FFBluetoothOptions
{
@@ -10,4 +11,5 @@ typedef struct FFBluetoothOptions
FFModuleArgs moduleArgs;
bool showDisconnected;
FFPercentConfig percent;
} FFBluetoothOptions;
+13 -4
View File
@@ -1,4 +1,4 @@
#include "common/bar.h"
#include "common/percent.h"
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "detection/brightness/brightness.h"
@@ -52,7 +52,7 @@ void ffPrintBrightness(FFBrightnessOptions* options)
if (instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT)
{
ffAppendPercentBar(&str, percent, 0, 100, 100);
ffPercentAppendBar(&str, percent, options->percent);
}
if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT)
@@ -60,7 +60,7 @@ void ffPrintBrightness(FFBrightnessOptions* options)
if(str.length > 0)
ffStrbufAppendC(&str, ' ');
ffAppendPercentNum(&str, percent, 10, 10, str.length > 0);
ffPercentAppendNum(&str, percent, options->percent, str.length > 0);
}
ffStrbufPutTo(&str, stdout);
@@ -68,7 +68,7 @@ void ffPrintBrightness(FFBrightnessOptions* options)
else
{
FF_STRBUF_AUTO_DESTROY valueStr = ffStrbufCreate();
ffAppendPercentNum(&valueStr, percent, 10, 10, false);
ffPercentAppendNum(&valueStr, percent, options->percent, false);
ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_BRIGHTNESS_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &valueStr},
{FF_FORMAT_ARG_TYPE_STRBUF, &item->name},
@@ -97,6 +97,9 @@ bool ffParseBrightnessCommandOptions(FFBrightnessOptions* options, const char* k
return true;
}
if (ffPercentParseCommandOptions(key, subKey, value, &options->percent))
return true;
return false;
}
@@ -119,6 +122,9 @@ void ffParseBrightnessJsonObject(FFBrightnessOptions* options, yyjson_val* modul
continue;
}
if (ffPercentParseJsonObject(key, val, &options->percent))
continue;
ffPrintError(FF_BRIGHTNESS_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
}
}
@@ -132,6 +138,8 @@ void ffGenerateBrightnessJsonConfig(FFBrightnessOptions* options, yyjson_mut_doc
if (defaultOptions.ddcciSleep != options->ddcciSleep)
yyjson_mut_obj_add_uint(doc, module, "ddcciSleep", options->ddcciSleep);
ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent);
}
void ffGenerateBrightnessJsonResult(FF_MAYBE_UNUSED FFBrightnessOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -197,6 +205,7 @@ void ffInitBrightnessOptions(FFBrightnessOptions* options)
ffOptionInitModuleArg(&options->moduleArgs);
options->ddcciSleep = 10;
options->percent = (FFPercentConfig) { 100, 100 };
}
void ffDestroyBrightnessOptions(FFBrightnessOptions* options)
+2
View File
@@ -3,6 +3,7 @@
// This file will be included in "fastfetch.h", do NOT put unnecessary things here
#include "common/option.h"
#include "common/percent.h"
typedef struct FFBrightnessOptions
{
@@ -10,4 +11,5 @@ typedef struct FFBrightnessOptions
FFModuleArgs moduleArgs;
uint32_t ddcciSleep; // ms
FFPercentConfig percent;
} FFBrightnessOptions;
+170
View File
@@ -0,0 +1,170 @@
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "detection/libc/libc.h"
#include "detection/camera/camera.h"
#include "modules/camera/camera.h"
#include "util/stringUtils.h"
#define FF_CAMERA_NUM_FORMAT_ARGS 5
static void printDevice(FFCameraOptions* options, const FFCameraResult* device, uint8_t index)
{
if(options->moduleArgs.outputFormat.length == 0)
{
ffPrintLogoAndKey(FF_CAMERA_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
ffStrbufWriteTo(&device->name, stdout);
if (device->colorspace.length > 0)
{
fputs(" - ", stdout);
ffStrbufWriteTo(&device->colorspace, stdout);
}
if (device->width > 0 && device->height > 0)
printf(" (%ux%u px)\n", (unsigned) device->width, (unsigned) device->height);
else
putchar('\n');
}
else
{
ffPrintFormat(FF_CAMERA_MODULE_NAME, index, &options->moduleArgs, FF_CAMERA_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_STRBUF, &device->name},
{FF_FORMAT_ARG_TYPE_STRBUF, &device->vendor},
{FF_FORMAT_ARG_TYPE_STRBUF, &device->colorspace},
{FF_FORMAT_ARG_TYPE_STRBUF, &device->id},
{FF_FORMAT_ARG_TYPE_UINT, &device->width},
{FF_FORMAT_ARG_TYPE_UINT, &device->height},
});
}
}
void ffPrintCamera(FFCameraOptions* options)
{
FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFCameraResult));
const char* error = ffDetectCamera(&result);
if (error)
{
ffPrintError(FF_CAMERA_MODULE_NAME, 0, &options->moduleArgs, "%s", error);
return;
}
if (result.length == 0)
{
ffPrintError(FF_CAMERA_MODULE_NAME, 0, &options->moduleArgs, "No camera found");
return;
}
for(uint32_t i = 0; i < result.length; i++)
{
uint8_t index = (uint8_t) (result.length == 1 ? 0 : i + 1);
printDevice(options, FF_LIST_GET(FFCameraResult, result, i), index);
}
FF_LIST_FOR_EACH(FFCameraResult, dev, result)
{
ffStrbufDestroy(&dev->name);
ffStrbufDestroy(&dev->id);
ffStrbufDestroy(&dev->colorspace);
}
}
bool ffParseCameraCommandOptions(FFCameraOptions* options, const char* key, const char* value)
{
const char* subKey = ffOptionTestPrefix(key, FF_CAMERA_MODULE_NAME);
if (!subKey) return false;
if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs))
return true;
return false;
}
void ffParseCameraJsonObject(FFCameraOptions* options, yyjson_val* module)
{
yyjson_val *key_, *val;
size_t idx, max;
yyjson_obj_foreach(module, idx, max, key_, val)
{
const char* key = yyjson_get_str(key_);
if(ffStrEqualsIgnCase(key, "type"))
continue;
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
continue;
ffPrintError(FF_CAMERA_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
}
}
void ffGenerateCameraJsonConfig(FFCameraOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
__attribute__((__cleanup__(ffDestroyCameraOptions))) FFCameraOptions defaultOptions;
ffInitCameraOptions(&defaultOptions);
ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs);
}
void ffGenerateCameraJsonResult(FF_MAYBE_UNUSED FFCameraOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
{
FF_LIST_AUTO_DESTROY result = ffListCreate(sizeof(FFCameraResult));
const char* error = ffDetectCamera(&result);
if (error)
{
yyjson_mut_obj_add_str(doc, module, "error", error);
return;
}
yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
FF_LIST_FOR_EACH(FFCameraResult, dev, result)
{
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &dev->name);
yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &dev->vendor);
yyjson_mut_obj_add_strbuf(doc, obj, "colorSpace", &dev->colorspace);
yyjson_mut_obj_add_strbuf(doc, obj, "id", &dev->id);
yyjson_mut_obj_add_uint(doc, obj, "width", dev->width);
yyjson_mut_obj_add_uint(doc, obj, "height", dev->height);
}
FF_LIST_FOR_EACH(FFCameraResult, dev, result)
{
ffStrbufDestroy(&dev->name);
ffStrbufDestroy(&dev->id);
ffStrbufDestroy(&dev->colorspace);
}
}
void ffPrintCameraHelpFormat(void)
{
ffPrintModuleFormatHelp(FF_CAMERA_MODULE_NAME, "{1} ({4}px x {5}px)", FF_CAMERA_NUM_FORMAT_ARGS, (const char* []) {
"Device name",
"Vendor",
"Color space",
"Identifier",
"Width (in px)",
"Height (in px)",
});
}
void ffInitCameraOptions(FFCameraOptions* options)
{
ffOptionInitModuleBaseInfo(
&options->moduleInfo,
FF_CAMERA_MODULE_NAME,
"Print available cameras",
ffParseCameraCommandOptions,
ffParseCameraJsonObject,
ffPrintCamera,
ffGenerateCameraJsonResult,
ffPrintCameraHelpFormat,
ffGenerateCameraJsonConfig
);
ffOptionInitModuleArg(&options->moduleArgs);
}
void ffDestroyCameraOptions(FFCameraOptions* options)
{
ffOptionDestroyModuleArg(&options->moduleArgs);
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "fastfetch.h"
#define FF_CAMERA_MODULE_NAME "Camera"
void ffPrintCamera(FFCameraOptions* options);
void ffInitCameraOptions(FFCameraOptions* options);
void ffDestroyCameraOptions(FFCameraOptions* options);
+11
View File
@@ -0,0 +1,11 @@
#pragma once
// This file will be included in "fastfetch.h", do NOT put unnecessary things here
#include "common/option.h"
typedef struct FFCameraOptions
{
FFModuleBaseInfo moduleInfo;
FFModuleArgs moduleArgs;
} FFCameraOptions;
+128 -18
View File
@@ -4,37 +4,55 @@
#include "modules/colors/colors.h"
#include "util/stringUtils.h"
static inline uint8_t min(uint8_t a, uint8_t b)
{
return a < b ? a : b;
}
static inline uint8_t max(uint8_t a, uint8_t b)
{
return a > b ? a : b;
}
void ffPrintColors(FFColorsOptions* options)
{
if(instance.config.display.pipe)
return;
ffPrintLogoAndKey(FF_COLORS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
bool flag = false;
if(options->paddingLeft > 0)
ffPrintCharTimes(' ', options->paddingLeft);
FF_STRBUF_AUTO_DESTROY result = ffStrbufCreateA(128);
if (options->symbol == FF_COLORS_SYMBOL_BLOCK)
{
// 4%d: Set the background color
// 3%d: Set the foreground color
for(uint8_t i = 0; i < 8; i++)
printf("\033[3%dm███", i);
for(uint8_t i = options->block.range[0]; i <= min(options->block.range[1], 7); i++)
{
ffStrbufAppendF(&result, "\e[3%dm", i);
for (uint8_t j = 0; j < options->block.width; j++)
ffStrbufAppendS(&result, "");
}
if (result.length > 0)
{
ffPrintLogoAndKey(FF_COLORS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
flag = true;
puts(FASTFETCH_TEXT_MODIFIER_RESET);
if(options->paddingLeft > 0)
ffPrintCharTimes(' ', options->paddingLeft);
ffLogoPrintLine();
if(options->paddingLeft > 0)
ffPrintCharTimes(' ', options->paddingLeft);
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_RESET);
ffStrbufPutTo(&result, stdout);
ffStrbufClear(&result);
}
// 1: Set everything to bolt. This causes normal colors on some systems to be bright.
// 4%d: Set the background to the not bright color
// 3%d: Set the foreground to the not bright color
// 10%d: Set the background to the bright color
// 9%d: Set the foreground to the bright color
for(uint8_t i = 0; i < 8; i++)
printf("\033[1;3%d;9%dm███", i, i);
for(uint8_t i = max(options->block.range[0], 8); i <= options->block.range[1]; i++)
{
ffStrbufAppendF(&result, "\e[1;9%dm", i - 8);
for (uint8_t j = 0; j < options->block.width; j++)
ffStrbufAppendS(&result, "");
}
}
else
{
@@ -49,10 +67,29 @@ void ffPrintColors(FFColorsOptions* options)
default: symbol = "███"; break;
}
for (int i = 8; i >= 1; --i)
printf("\e[3%dm%s ", i, symbol);
ffStrbufAppendF(&result, "\e[3%dm%s ", i, symbol);
}
puts(FASTFETCH_TEXT_MODIFIER_RESET);
if (result.length > 0)
{
if (flag)
ffLogoPrintLine();
else
{
ffPrintLogoAndKey(FF_COLORS_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
flag = true;
}
if(options->paddingLeft > 0)
ffPrintCharTimes(' ', options->paddingLeft);
ffStrbufAppendS(&result, FASTFETCH_TEXT_MODIFIER_RESET);
ffStrbufPutTo(&result, stdout);
}
if (!flag)
{
ffPrintError(FF_COLORS_MODULE_NAME, 0, &options->moduleArgs, "%s", "Nothing to print");
}
}
bool ffParseColorsCommandOptions(FFColorsOptions* options, const char* key, const char* value)
@@ -82,6 +119,24 @@ bool ffParseColorsCommandOptions(FFColorsOptions* options, const char* key, cons
return true;
}
if (ffStrEqualsIgnCase(subKey, "block-width"))
{
options->block.width = (uint8_t) ffOptionParseUInt32(key, value);
return true;
}
if (ffStrEqualsIgnCase(subKey, "block-range-start"))
{
options->block.range[0] = min((uint8_t) ffOptionParseUInt32(key, value), 15);
return true;
}
if (ffStrEqualsIgnCase(subKey, "block-range-end"))
{
options->block.range[1] = min((uint8_t) ffOptionParseUInt32(key, value), 15);
return true;
}
return false;
}
@@ -123,6 +178,40 @@ void ffParseColorsJsonObject(FFColorsOptions* options, yyjson_val* module)
continue;
}
if (ffStrEqualsIgnCase(key, "block"))
{
if (!yyjson_is_obj(val))
ffPrintErrorString(FF_COLORS_MODULE_NAME, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s value: must be an object", key);
else
{
yyjson_val* width = yyjson_obj_get(val, "width");
if (width)
options->block.width = (uint8_t) yyjson_get_uint(width);
yyjson_val* range = yyjson_obj_get(val, "range");
if (range)
{
if (!yyjson_is_arr(range) || yyjson_arr_size(range) != 2)
ffPrintErrorString(FF_COLORS_MODULE_NAME, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: must be an array of 2 elements", key);
else
{
uint8_t start = (uint8_t) yyjson_get_uint(yyjson_arr_get(range, 0));
uint8_t end = (uint8_t) yyjson_get_uint(yyjson_arr_get(range, 1));
if (start > end)
ffPrintErrorString(FF_COLORS_MODULE_NAME, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: range[0] > range[1]", key);
else if (end > 15)
ffPrintErrorString(FF_COLORS_MODULE_NAME, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Invalid %s.range value: range[1] > 15", key);
else
{
options->block.range[0] = start;
options->block.range[1] = end;
}
}
}
}
continue;
}
ffPrintErrorString(FF_COLORS_MODULE_NAME, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "Unknown JSON key %s", key);
}
}
@@ -149,6 +238,23 @@ void ffGenerateColorsJsonConfig(FFColorsOptions* options, yyjson_mut_doc* doc, y
if (defaultOptions.paddingLeft != options->paddingLeft)
yyjson_mut_obj_add_uint(doc, module, "paddingLeft", options->paddingLeft);
{
yyjson_mut_val* block = yyjson_mut_obj(doc);
if (defaultOptions.block.width != options->block.width)
yyjson_mut_obj_add_uint(doc, block, "width", options->block.width);
if (memcmp(defaultOptions.block.range, options->block.range, sizeof(options->block.range)) != 0)
{
yyjson_mut_val* range = yyjson_mut_obj_add_arr(doc, block, "range");
for (uint8_t i = 0; i < 2; i++)
yyjson_mut_arr_add_uint(doc, range, options->block.range[i]);
}
if (yyjson_mut_obj_size(block) > 0)
yyjson_mut_obj_add_val(doc, module, "block", block);
}
}
void ffInitColorsOptions(FFColorsOptions* options)
@@ -168,6 +274,10 @@ void ffInitColorsOptions(FFColorsOptions* options)
ffStrbufSetStatic(&options->moduleArgs.key, " ");
options->symbol = FF_COLORS_SYMBOL_BLOCK;
options->paddingLeft = 0;
options->block = (FFBlockConfig) {
.width = 3,
.range = { 0, 15 },
};
}
void ffDestroyColorsOptions(FF_MAYBE_UNUSED FFColorsOptions* options)
+7
View File
@@ -14,6 +14,12 @@ typedef enum FFColorsSymbol
FF_COLORS_SYMBOL_STAR,
} FFColorsSymbol;
typedef struct FFBlockConfig
{
uint8_t width;
uint8_t range[2];
} FFBlockConfig;
typedef struct FFColorsOptions
{
FFModuleBaseInfo moduleInfo;
@@ -21,4 +27,5 @@ typedef struct FFColorsOptions
FFColorsSymbol symbol;
uint32_t paddingLeft;
FFBlockConfig block;
} FFColorsOptions;
+16 -7
View File
@@ -1,6 +1,6 @@
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "common/bar.h"
#include "common/percent.h"
#include "detection/cpuusage/cpuusage.h"
#include "modules/cpuusage/cpuusage.h"
#include "util/stringUtils.h"
@@ -52,12 +52,12 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options)
if (!options->separate)
{
if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT)
ffAppendPercentBar(&str, avgValue, 0, 50, 80);
ffPercentAppendBar(&str, avgValue, options->percent);
if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT)
{
if(str.length > 0)
ffStrbufAppendC(&str, ' ');
ffAppendPercentNum(&str, avgValue, 50, 80, str.length > 0);
ffPercentAppendNum(&str, avgValue, options->percent, str.length > 0);
}
}
else
@@ -66,7 +66,7 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options)
{
if(str.length > 0)
ffStrbufAppendC(&str, ' ');
ffAppendPercentNum(&str, *percent, 50, 80, false);
ffPercentAppendNum(&str, *percent, options->percent, false);
}
}
ffStrbufPutTo(&str, stdout);
@@ -74,11 +74,11 @@ void ffPrintCPUUsage(FFCPUUsageOptions* options)
else
{
FF_STRBUF_AUTO_DESTROY avgStr = ffStrbufCreate();
ffAppendPercentNum(&avgStr, avgValue, 50, 80, false);
ffPercentAppendNum(&avgStr, avgValue, options->percent, false);
FF_STRBUF_AUTO_DESTROY minStr = ffStrbufCreate();
ffAppendPercentNum(&minStr, minValue, 50, 80, false);
ffPercentAppendNum(&minStr, minValue, options->percent, false);
FF_STRBUF_AUTO_DESTROY maxStr = ffStrbufCreate();
ffAppendPercentNum(&maxStr, maxValue, 50, 80, false);
ffPercentAppendNum(&maxStr, maxValue, options->percent, false);
ffPrintFormat(FF_CPUUSAGE_DISPLAY_NAME, 0, &options->moduleArgs, FF_CPUUSAGE_NUM_FORMAT_ARGS, (FFformatarg[]){
{FF_FORMAT_ARG_TYPE_STRBUF, &avgStr},
{FF_FORMAT_ARG_TYPE_STRBUF, &maxStr},
@@ -102,6 +102,9 @@ bool ffParseCPUUsageCommandOptions(FFCPUUsageOptions* options, const char* key,
return true;
}
if (ffPercentParseCommandOptions(key, subKey, value, &options->percent))
return true;
return false;
}
@@ -124,6 +127,9 @@ void ffParseCPUUsageJsonObject(FFCPUUsageOptions* options, yyjson_val* module)
continue;
}
if (ffPercentParseJsonObject(key, val, &options->percent))
continue;
ffPrintError(FF_CPUUSAGE_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
}
}
@@ -137,6 +143,8 @@ void ffGenerateCPUUsageJsonConfig(FFCPUUsageOptions* options, yyjson_mut_doc* do
if (options->separate != defaultOptions.separate)
yyjson_mut_obj_add_bool(doc, module, "separate", options->separate);
ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent);
}
void ffGenerateCPUUsageJsonResult(FF_MAYBE_UNUSED FFCPUUsageOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -182,6 +190,7 @@ void ffInitCPUUsageOptions(FFCPUUsageOptions* options)
);
ffOptionInitModuleArg(&options->moduleArgs);
options->separate = false;
options->percent = (FFPercentConfig) { 50, 80 };
}
void ffDestroyCPUUsageOptions(FFCPUUsageOptions* options)
+2
View File
@@ -3,6 +3,7 @@
// This file will be included in "fastfetch.h", do NOT put unnecessary things here
#include "common/option.h"
#include "common/percent.h"
typedef struct FFCPUUsageOptions
{
@@ -10,4 +11,5 @@ typedef struct FFCPUUsageOptions
FFModuleArgs moduleArgs;
bool separate;
FFPercentConfig percent;
} FFCPUUsageOptions;
+37 -63
View File
@@ -9,7 +9,7 @@
#pragma GCC diagnostic ignored "-Wformat" // warning: unknown conversion type character 'F' in format
#define FF_DATETIME_DISPLAY_NAME "Date & Time"
#define FF_DATETIME_NUM_FORMAT_ARGS 20
#define FF_DATETIME_NUM_FORMAT_ARGS 22
typedef struct FFDateTimeResult
{
@@ -17,23 +17,25 @@ typedef struct FFDateTimeResult
uint16_t year; //2022
uint8_t yearShort; //22
uint8_t month; //2
FFstrbuf monthPretty; //02
FFstrbuf monthName; //February
FFstrbuf monthNameShort; //Feb
char monthPretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //02
char monthName[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //February
char monthNameShort[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //Feb
uint8_t week; //8
FFstrbuf weekday; //Monday
FFstrbuf weekdayShort; //Mon
char weekday[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //Monday
char weekdayShort[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //Mon
uint16_t dayInYear; //52
uint8_t dayInMonth; //21
uint8_t dayInWeek; //1
uint8_t hour; //15
FFstrbuf hourPretty; //15
char hourPretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //15
uint8_t hour12; //3
FFstrbuf hour12Pretty; //03
char hour12Pretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //03
uint8_t minute; //18
FFstrbuf minutePretty; //18
char minutePretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //18
uint8_t second; //37
FFstrbuf secondPretty; //37
char secondPretty[FASTFETCH_STRBUF_DEFAULT_ALLOC]; //37
char offsetFromUtc[FASTFETCH_STRBUF_DEFAULT_ALLOC];
char timezoneName[FASTFETCH_STRBUF_DEFAULT_ALLOC];
} FFDateTimeResult;
void ffPrintDateTimeFormat(struct tm* tm, const FFModuleArgs* moduleArgs)
@@ -43,80 +45,50 @@ void ffPrintDateTimeFormat(struct tm* tm, const FFModuleArgs* moduleArgs)
result.year = (uint16_t) (tm->tm_year + 1900);
result.yearShort = (uint8_t) (result.year % 100);
result.month = (uint8_t) (tm->tm_mon + 1);
ffStrbufInitA(&result.monthPretty, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.monthPretty.length = (uint32_t) strftime(result.monthPretty.chars, ffStrbufGetFree(&result.monthPretty), "%m", tm);
ffStrbufInitA(&result.monthName, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.monthName.length = (uint32_t) strftime(result.monthName.chars, ffStrbufGetFree(&result.monthName), "%B", tm);
ffStrbufInitA(&result.monthNameShort, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.monthNameShort.length = (uint32_t) strftime(result.monthNameShort.chars, ffStrbufGetFree(&result.monthNameShort), "%b", tm);
strftime(result.monthPretty, sizeof(result.monthPretty), "%m", tm);
strftime(result.monthName, sizeof(result.monthName), "%B", tm);
strftime(result.monthNameShort, sizeof(result.monthNameShort), "%b", tm);
result.week = (uint8_t) (tm->tm_yday / 7 + 1);
ffStrbufInitA(&result.weekday, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.weekday.length = (uint32_t) strftime(result.weekday.chars, ffStrbufGetFree(&result.weekday), "%A", tm);
ffStrbufInitA(&result.weekdayShort, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.weekdayShort.length = (uint32_t) strftime(result.weekdayShort.chars, ffStrbufGetFree(&result.weekdayShort), "%a", tm);
strftime(result.weekday, sizeof(result.weekday), "%A", tm);
strftime(result.weekdayShort, sizeof(result.weekdayShort), "%a", tm);
result.dayInYear = (uint8_t) (tm->tm_yday + 1);
result.dayInMonth = (uint8_t) tm->tm_mday;
result.dayInWeek = tm->tm_wday == 0 ? 7 : (uint8_t) tm->tm_wday;
result.hour = (uint8_t) tm->tm_hour;
ffStrbufInitA(&result.hourPretty, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.hourPretty.length = (uint32_t) strftime(result.hourPretty.chars, ffStrbufGetFree(&result.hourPretty), "%H", tm);
strftime(result.hourPretty, sizeof(result.hourPretty), "%H", tm);
result.hour12 = (uint8_t) (result.hour % 12);
ffStrbufInitA(&result.hour12Pretty, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.hour12Pretty.length = (uint32_t) strftime(result.hour12Pretty.chars, ffStrbufGetFree(&result.hour12Pretty), "%I", tm);
strftime(result.hour12Pretty, sizeof(result.hour12Pretty), "%I", tm);
result.minute = (uint8_t) tm->tm_min;
ffStrbufInitA(&result.minutePretty, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.minutePretty.length = (uint32_t) strftime(result.minutePretty.chars, ffStrbufGetFree(&result.minutePretty), "%M", tm);
strftime(result.minutePretty, sizeof(result.minutePretty), "%M", tm);
result.second = (uint8_t) tm->tm_sec;
ffStrbufInitA(&result.secondPretty, FASTFETCH_STRBUF_DEFAULT_ALLOC);
result.secondPretty.length = (uint32_t) strftime(result.secondPretty.chars, ffStrbufGetFree(&result.secondPretty), "%S", tm);
strftime(result.secondPretty, sizeof(result.secondPretty), "%S", tm);
strftime(result.offsetFromUtc, sizeof(result.offsetFromUtc), "%z", tm);
strftime(result.timezoneName, sizeof(result.timezoneName), "%Z", tm);
ffPrintFormat(FF_DATETIME_DISPLAY_NAME, 0, moduleArgs, FF_DATETIME_NUM_FORMAT_ARGS, (FFformatarg[]) {
{FF_FORMAT_ARG_TYPE_UINT16, &result.year}, // 1
{FF_FORMAT_ARG_TYPE_UINT8, &result.yearShort}, // 2
{FF_FORMAT_ARG_TYPE_UINT8, &result.month}, // 3
{FF_FORMAT_ARG_TYPE_STRBUF, &result.monthPretty}, // 4
{FF_FORMAT_ARG_TYPE_STRBUF, &result.monthName}, // 5
{FF_FORMAT_ARG_TYPE_STRBUF, &result.monthNameShort}, // 6
{FF_FORMAT_ARG_TYPE_STRING, result.monthPretty}, // 4
{FF_FORMAT_ARG_TYPE_STRING, result.monthName}, // 5
{FF_FORMAT_ARG_TYPE_STRING, result.monthNameShort}, // 6
{FF_FORMAT_ARG_TYPE_UINT8, &result.week}, // 7
{FF_FORMAT_ARG_TYPE_STRBUF, &result.weekday}, // 8
{FF_FORMAT_ARG_TYPE_STRBUF, &result.weekdayShort}, // 9
{FF_FORMAT_ARG_TYPE_STRING, result.weekday}, // 8
{FF_FORMAT_ARG_TYPE_STRING, result.weekdayShort}, // 9
{FF_FORMAT_ARG_TYPE_UINT16, &result.dayInYear}, // 10
{FF_FORMAT_ARG_TYPE_UINT8, &result.dayInMonth}, // 11
{FF_FORMAT_ARG_TYPE_UINT8, &result.dayInWeek}, // 12
{FF_FORMAT_ARG_TYPE_UINT8, &result.hour}, // 13
{FF_FORMAT_ARG_TYPE_STRBUF, &result.hourPretty}, // 14
{FF_FORMAT_ARG_TYPE_STRING, result.hourPretty}, // 14
{FF_FORMAT_ARG_TYPE_UINT8, &result.hour12}, // 15
{FF_FORMAT_ARG_TYPE_STRBUF, &result.hour12Pretty}, // 16
{FF_FORMAT_ARG_TYPE_STRING, result.hour12Pretty}, // 16
{FF_FORMAT_ARG_TYPE_UINT8, &result.minute}, // 17
{FF_FORMAT_ARG_TYPE_STRBUF, &result.minutePretty}, // 18
{FF_FORMAT_ARG_TYPE_STRING, result.minutePretty}, // 18
{FF_FORMAT_ARG_TYPE_UINT8, &result.second}, // 19
{FF_FORMAT_ARG_TYPE_STRBUF, &result.secondPretty} // 20
{FF_FORMAT_ARG_TYPE_STRING, result.secondPretty}, // 20
{FF_FORMAT_ARG_TYPE_STRING, result.offsetFromUtc}, // 21
{FF_FORMAT_ARG_TYPE_STRING, result.timezoneName}, // 22
});
ffStrbufDestroy(&result.hour12Pretty);
ffStrbufDestroy(&result.hourPretty);
ffStrbufDestroy(&result.minutePretty);
ffStrbufDestroy(&result.monthName);
ffStrbufDestroy(&result.monthNameShort);
ffStrbufDestroy(&result.monthPretty);
ffStrbufDestroy(&result.secondPretty);
ffStrbufDestroy(&result.weekday);
ffStrbufDestroy(&result.weekdayShort);
}
void ffPrintDateTime(FFDateTimeOptions* options)
@@ -205,7 +177,9 @@ void ffPrintDateTimeHelpFormat(void)
"minute",
"minute with leading zero",
"second",
"second with leading zero"
"second with leading zero",
"offset from UTC in the ISO 8601 format",
"locale-dependent timezone name or abbreviation",
});
}
+14 -5
View File
@@ -1,7 +1,7 @@
#include "common/printing.h"
#include "common/jsonconfig.h"
#include "common/parsing.h"
#include "common/bar.h"
#include "common/percent.h"
#include "detection/disk/disk.h"
#include "modules/disk/disk.h"
#include "util/stringUtils.h"
@@ -59,7 +59,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk)
{
if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_BAR_BIT)
{
ffAppendPercentBar(&str, bytesPercentage, 0, 50, 80);
ffPercentAppendBar(&str, bytesPercentage, options->percent);
ffStrbufAppendC(&str, ' ');
}
@@ -68,7 +68,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk)
if(instance.config.display.percentType & FF_PERCENTAGE_TYPE_NUM_BIT)
{
ffAppendPercentNum(&str, bytesPercentage, 50, 80, str.length > 0);
ffPercentAppendNum(&str, bytesPercentage, options->percent, str.length > 0);
ffStrbufAppendC(&str, ' ');
}
}
@@ -104,10 +104,10 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk)
else
{
FF_STRBUF_AUTO_DESTROY bytesPercentageStr = ffStrbufCreate();
ffAppendPercentNum(&bytesPercentageStr, bytesPercentage, 50, 80, false);
ffPercentAppendNum(&bytesPercentageStr, bytesPercentage, options->percent, false);
FF_STRBUF_AUTO_DESTROY filesPercentageStr = ffStrbufCreate();
double filesPercentage = disk->filesTotal > 0 ? ((double) disk->filesUsed / (double) disk->filesTotal) * 100.0 : 0;
ffAppendPercentNum(&filesPercentageStr, filesPercentage, 50, 80, false);
ffPercentAppendNum(&filesPercentageStr, filesPercentage, options->percent, false);
bool isExternal = !!(disk->type & FF_DISK_VOLUME_TYPE_EXTERNAL_BIT);
bool isHidden = !!(disk->type & FF_DISK_VOLUME_TYPE_HIDDEN_BIT);
@@ -278,6 +278,9 @@ bool ffParseDiskCommandOptions(FFDiskOptions* options, const char* key, const ch
return true;
}
if (ffPercentParseCommandOptions(key, subKey, value, &options->percent))
return true;
return false;
}
@@ -354,6 +357,9 @@ void ffParseDiskJsonObject(FFDiskOptions* options, yyjson_val* module)
continue;
}
if (ffPercentParseJsonObject(key, val, &options->percent))
continue;
ffPrintError(FF_DISK_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
}
}
@@ -388,6 +394,8 @@ void ffGenerateDiskJsonConfig(FFDiskOptions* options, yyjson_mut_doc* doc, yyjso
if (defaultOptions.calcType != options->calcType)
yyjson_mut_obj_add_bool(doc, module, "useAvailable", options->calcType == FF_DISK_CALC_TYPE_AVAILABLE);
ffPercentGenerateJsonConfig(doc, module, defaultOptions.percent, options->percent);
}
void ffGenerateDiskJsonResult(FFDiskOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
@@ -476,6 +484,7 @@ void ffInitDiskOptions(FFDiskOptions* options)
ffStrbufInit(&options->folders);
options->showTypes = FF_DISK_VOLUME_TYPE_REGULAR_BIT | FF_DISK_VOLUME_TYPE_EXTERNAL_BIT | FF_DISK_VOLUME_TYPE_READONLY_BIT;
options->calcType = FF_DISK_CALC_TYPE_FREE;
options->percent = (FFPercentConfig) { 50, 80 };
}
void ffDestroyDiskOptions(FFDiskOptions* options)

Some files were not shown because too many files have changed in this diff Show More