├── .clang-format
├── .clang-tidy
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
└── workflows
│ ├── ci.yml
│ ├── flakehub.yml
│ └── update-flake.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── MANUAL.md
├── Makefile
├── README.md
├── albafetch.conf
├── debian
└── makedeb.sh
├── default.nix
├── example_logo.txt
├── flake.lock
├── flake.nix
├── images
├── albafetch.png
├── albafetch_demo.png
├── albafetch_demo_default.png
├── time_albafetch.png
├── time_neofetch.png
└── v2.0.png
├── meson.build
├── nix
└── package.nix
└── src
├── config
├── config.c
├── config.h
├── parsing.c
└── parsing.h
├── debug.c
├── info
├── battery.c
├── bios.c
├── colors.c
├── cpu.c
├── cursor_theme.c
├── date.c
├── desktop.c
├── gpu.c
├── gtk_theme.c
├── host.c
├── hostname.c
├── icon_theme.c
├── info.h
├── kernel.c
├── light_colors.c
├── local_ip.c
├── login_shell.c
├── memory.c
├── os.c
├── packages.c
├── public_ip.c
├── pwd.c
├── shell.c
├── swap.c
├── term.c
├── uptime.c
└── user.c
├── macos
├── bsdwrap.c
├── bsdwrap.h
├── macos_gpu_string.m
├── macos_infos.c
└── macos_infos.h
├── main.c
├── optdeps
├── glib.c
├── libpci.c
└── optdeps.h
└── utils
├── logos.h
├── queue.c
├── queue.h
├── return.h
├── utils.c
├── utils.h
├── wrappers.c
└── wrappers.h
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html
3 | # Based on Hyprland's
4 | Language: Cpp
5 | BasedOnStyle: LLVM
6 |
7 | AccessModifierOffset: -2
8 | AlignAfterOpenBracket: Align
9 | AlignConsecutiveAssignments: None
10 | AlignConsecutiveDeclarations: None
11 | AlignConsecutiveMacros: true
12 | AlignEscapedNewlines: Right
13 | AlignOperands: false
14 | AlignTrailingComments: true
15 | AllowAllArgumentsOnNextLine: true
16 | AllowAllConstructorInitializersOnNextLine: true
17 | AllowAllParametersOfDeclarationOnNextLine: true
18 | AllowShortBlocksOnASingleLine: true
19 | AllowShortCaseLabelsOnASingleLine: true
20 | AllowShortFunctionsOnASingleLine: Empty
21 | AllowShortIfStatementsOnASingleLine: Never
22 | AllowShortLambdasOnASingleLine: All
23 | AllowShortLoopsOnASingleLine: false
24 | AlwaysBreakAfterDefinitionReturnType: None
25 | AlwaysBreakAfterReturnType: None
26 | AlwaysBreakBeforeMultilineStrings: false
27 | AlwaysBreakTemplateDeclarations: Yes
28 | BreakBeforeBraces: Attach
29 | BreakBeforeTernaryOperators: false
30 | BreakConstructorInitializers: AfterColon
31 | ColumnLimit: 180
32 | CompactNamespaces: false
33 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
34 | ExperimentalAutoDetectBinPacking: false
35 | FixNamespaceComments: false
36 | IncludeBlocks: Preserve
37 | IndentCaseLabels: true
38 | IndentWidth: 4
39 | InsertNewlineAtEOF: true
40 | PointerAlignment: Right
41 | ReflowComments: false
42 | SortIncludes: false
43 | SortUsingDeclarations: false
44 | SpaceAfterCStyleCast: false
45 | SpaceAfterLogicalNot: false
46 | SpaceAfterTemplateKeyword: true
47 | SpaceBeforeCtorInitializerColon: true
48 | SpaceBeforeInheritanceColon: true
49 | SpaceBeforeParens: false
50 | SpaceBeforeRangeBasedForLoopColon: true
51 | SpaceInEmptyParentheses: false
52 | SpacesBeforeTrailingComments: 1
53 | SpacesInAngles: false
54 | SpacesInContainerLiterals: false
55 | SpacesInCStyleCastParentheses: false
56 | SpacesInParentheses: false
57 | SpacesInSquareBrackets: false
58 | Standard: Auto
59 | TabWidth: 4
60 | UseTab: Never
61 |
62 | AllowShortEnumsOnASingleLine: false
63 |
64 | BraceWrapping:
65 | AfterEnum: false
66 |
67 | NamespaceIndentation: All
68 |
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | WarningsAsErrors: '*'
2 | HeaderFilterRegex: '.*\.hpp'
3 | FormatStyle: file
4 | Checks: >
5 | -*,
6 | bugprone-*,
7 | -bugprone-easily-swappable-parameters,
8 | -bugprone-forward-declararion-namespace,
9 | -bugprone-forward-declararion-namespace,
10 | -bugprone-macro-parentheses,
11 | -bugprone-narrowing-conversions,
12 | -bugprone-branch-clone,
13 | -bugprone-assignment-in-if-condition,
14 | concurrency-*,
15 | -concurrency-mt-unsafe,
16 | cppcoreguidelines-*,
17 | -cppcoreguidelines-owning-memory,
18 | -cppcoreguidelines-avoid-magic-numbers,
19 | -cppcoreguidelines-pro-bounds-constant-array-index,
20 | -cppcoreguidelines-avoid-const-or-ref-data-members,
21 | -cppcoreguidelines-non-private-member-variables-in-classes,
22 | -cppcoreguidelines-avoid-goto,
23 | -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
24 | -cppcoreguidelines-avoid-do-while,
25 | -cppcoreguidelines-avoid-non-const-global-variables,
26 | -cppcoreguidelines-special-member-functions,
27 | -cppcoreguidelines-explicit-virtual-functions,
28 | -cppcoreguidelines-avoid-c-arrays,
29 | -cppcoreguidelines-pro-bounds-pointer-arithmetic,
30 | -cppcoreguidelines-narrowing-conversions,
31 | -cppcoreguidelines-pro-type-union-access,
32 | -cppcoreguidelines-pro-type-member-init,
33 | -cppcoreguidelines-macro-usage,
34 | -cppcoreguidelines-macro-to-enum,
35 | -cppcoreguidelines-init-variables,
36 | -cppcoreguidelines-pro-type-cstyle-cast,
37 | -cppcoreguidelines-pro-type-vararg,
38 | -cppcoreguidelines-pro-type-reinterpret-cast,
39 | google-global-names-in-headers,
40 | -google-readability-casting,
41 | google-runtime-operator,
42 | misc-*,
43 | -misc-unused-parameters,
44 | -misc-no-recursion,
45 | -misc-non-private-member-variables-in-classes,
46 | -misc-include-cleaner,
47 | -misc-use-anonymous-namespace,
48 | -misc-const-correctness,
49 | modernize-*,
50 | -modernize-return-braced-init-list,
51 | -modernize-use-trailing-return-type,
52 | -modernize-use-using,
53 | -modernize-use-override,
54 | -modernize-avoid-c-arrays,
55 | -modernize-macro-to-enum,
56 | -modernize-loop-convert,
57 | -modernize-use-nodiscard,
58 | -modernize-pass-by-value,
59 | -modernize-use-auto,
60 | performance-*,
61 | -performance-avoid-endl,
62 | -performance-unnecessary-value-param,
63 | portability-std-allocator-const,
64 | readability-*,
65 | -readability-function-cognitive-complexity,
66 | -readability-function-size,
67 | -readability-identifier-length,
68 | -readability-magic-numbers,
69 | -readability-uppercase-literal-suffix,
70 | -readability-braces-around-statements,
71 | -readability-redundant-access-specifiers,
72 | -readability-else-after-return,
73 | -readability-container-data-pointer,
74 | -readability-implicit-bool-conversion,
75 | -readability-avoid-nested-conditional-operator,
76 | -readability-redundant-member-init,
77 | -readability-redundant-string-init,
78 | -readability-avoid-const-params-in-decls,
79 | -readability-named-parameter,
80 | -readability-convert-member-functions-to-static,
81 | -readability-qualified-auto,
82 | -readability-make-member-function-const,
83 | -readability-isolate-declaration,
84 | -readability-inconsistent-declaration-parameter-name,
85 | -clang-diagnostic-error,
86 |
87 | CheckOptions:
88 | performance-for-range-copy.WarnOnAllAutoCopies: true
89 | performance-inefficient-string-concatenation.StrictMode: true
90 | readability-braces-around-statements.ShortStatementLines: 0
91 | readability-identifier-naming.ClassCase: CamelCase
92 | readability-identifier-naming.ClassIgnoredRegexp: I.*
93 | readability-identifier-naming.ClassPrefix: C
94 | readability-identifier-naming.EnumCase: CamelCase
95 | readability-identifier-naming.EnumPrefix: e
96 | readability-identifier-naming.EnumConstantCase: UPPER_CASE
97 | readability-identifier-naming.FunctionCase: camelBack
98 | readability-identifier-naming.NamespaceCase: CamelCase
99 | readability-identifier-naming.NamespacePrefix: N
100 | readability-identifier-naming.StructPrefix: S
101 | readability-identifier-naming.StructCase: CamelCase
102 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: alba4k
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help me improve
4 | title: "[Bug Report]"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **Expected behavior**
14 | A clear and concise description of what you expected to happen.
15 |
16 | **Screenshots**
17 | If applicable, add screenshots to help explain your problem.
18 |
19 | **Desktop (please complete the following information):**
20 | - OS: [e.g. Arch Linux]
21 | - Terminal [e.g. Kitty, Alacritty]
22 |
23 | **Possibly relevant config lines:**
24 | - Post a screenshot of / copy paste part the relevant config file
25 |
26 | **Additional context**
27 | Add any other context about the problem here.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[Feature Request]"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated that [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen or to be added.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "github-actions" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 | commit-message:
13 | prefix: "actions"
14 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on:
4 | pull_request:
5 | push:
6 | workflow_dispatch:
7 |
8 | jobs:
9 | build:
10 | strategy:
11 | matrix:
12 | os: [ubuntu-latest, macos-latest]
13 | include:
14 | - os: ubuntu-latest
15 | platform: linux
16 | - os: macos-latest
17 | platform: darwin
18 |
19 | runs-on: ${{ matrix.os }}
20 | steps:
21 | - uses: actions/checkout@v4
22 |
23 | - uses: cachix/install-nix-action@v31
24 |
25 | - uses: cachix/cachix-action@v16
26 | with:
27 | name: albafetch
28 | authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
29 |
30 | - name: build (linux/x64)
31 | if: runner.os == 'Linux'
32 | run: nix build -L --accept-flake-config .#albafetch-static
33 |
34 | - name: build (darwin/x64)
35 | if: runner.os == 'macOS'
36 | run: nix build -L --accept-flake-config
37 |
38 | - name: test
39 | run: ./result/bin/albafetch
40 |
41 | - uses: actions/upload-artifact@v4
42 | if: runner.os == 'Linux'
43 | with:
44 | name: albafetch-linux-x64-static
45 | path: ${{ github.workspace }}/result/bin/albafetch
46 |
47 | - uses: actions/upload-artifact@v4
48 | if: runner.os == 'macOS'
49 | with:
50 | name: albafetch-darwin-x64
51 | path: ${{ github.workspace }}/result/bin/albafetch
52 |
53 | - name: build (linux/aarch64-multiplatform)
54 | if: runner.os == 'Linux'
55 | run: nix build -L --accept-flake-config .#albafetch-arm
56 |
57 | - uses: actions/upload-artifact@v4
58 | if: runner.os == 'Linux'
59 | with:
60 | name: albafetch-linux-aarch64-static
61 | path: ${{ github.workspace }}/result/bin/albafetch
62 |
--------------------------------------------------------------------------------
/.github/workflows/flakehub.yml:
--------------------------------------------------------------------------------
1 | name: Publish tags to FlakeHub
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | workflow_dispatch:
8 |
9 | jobs:
10 | publish:
11 | runs-on: ubuntu-latest
12 | permissions:
13 | id-token: write
14 | contents: read
15 |
16 | steps:
17 | - uses: actions/checkout@v4
18 | - uses: DeterminateSystems/nix-installer-action@main
19 |
20 | - uses: DeterminateSystems/flakehub-push@main
21 | with:
22 | visibility: "public"
23 | rolling: true
24 |
--------------------------------------------------------------------------------
/.github/workflows/update-flake.yml:
--------------------------------------------------------------------------------
1 | name: Update Nix Flake lock
2 |
3 | on:
4 | schedule:
5 | # run every saturday
6 | - cron: "0 0 * * 6"
7 | workflow_dispatch:
8 |
9 | permissions:
10 | contents: write
11 | pull-requests: write
12 |
13 | jobs:
14 | update-flake:
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 |
20 | - uses: cachix/install-nix-action@v31
21 | with:
22 | github_access_token: ${{ github.token }}
23 |
24 | - uses: DeterminateSystems/update-flake-lock@v25
25 | id: update
26 | with:
27 | commit-msg: "flake: update inputs"
28 | pr-title: "flake: update inputs"
29 | token: ${{ github.token }}
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | .idea
3 | build
4 | debian/albafetch*
5 |
6 | # nix stuff
7 | .direnv/
8 | result*
9 | repl-result-out*
10 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changes since v4.2.1
2 |
3 | ## New Features
4 |
5 | ### Modules
6 | * Added a `swap` module that prints the used and total swap on linux
7 | * The `cpu` modules now prints 2 decimal digits is the frequency is below 1 GHz
8 |
9 | ### Config syntax
10 | * Custom ascii arts will now print in the specified color by default
11 | * Added `swap_label`, the label for the new swap module
12 | * Added `swap_perc`, whether the used swap percentage should be printed
13 |
14 | ### Command line arguments
15 | * Added `--version` (`-v` for short), prints version and build commit
16 |
17 | ### Other
18 | * Added a logo for [Rocky Linux](https://rockylinux.org)
19 |
20 | ## Changes
21 | * Updated the [Garuda Linux](https://garudalinux.org) logo
22 | * Changed return values to be more clear than 0 or 1
23 | * User errors are now handled gracefully
24 | * term will not print `Apple Terminal` instead of `Apple_Terminal`
25 |
26 | ## Bug fixes
27 |
28 | ### Noticeable fixes
29 | * Packages should be counted faster for dpkg and especially snap
30 | * Alacritty will now be properly recognized even with `general.ipc_socket = false`
31 | * `gpu` should now print all gpus even when libpci doesn't work
32 | * Fixed `pwd_path` not working
33 | * Should now exit on OOM, not segfault
34 |
35 | ### Technical fixes
36 | * Reduced the size of default logos
37 | * Moved some functions from `src/utils/utils.c` to `src/config/config.c` and `src/config/config.c`.
38 | Planning on rewriting config parsing and reducing `src/utils/utils.c` even more.
39 | * Minor memory safety improvements
40 |
41 | ## Dependencies
42 | * sqlite3 is now needed to build the project
43 | * meson, ninja and pkg-config are now used in the Makefile
44 | * glib is now an optional dependency. If not installed at compile time, custom implementations will be used
45 | * libpci is not an optional dependency at compile time too
46 |
47 | ---
48 |
49 | ##### © Aaron Blasko
50 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT/X Consortium License
2 |
3 | © 2022 Aaron Blasko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/MANUAL.md:
--------------------------------------------------------------------------------
1 | # Table of contents
2 | 1. [Configuration](#configuration)
3 | * [file location](#which-file-is-used)
4 | * [config syntax](#syntax)
5 | 2. [Command-line Arguments](#command-line-arguments)
6 | 3. [Return Codes](#return-codes-and-errors)
7 | * [0](#return-code-0)
8 | * [1](#error-1)
9 | * [-1](#error--1-255)
10 |
11 | # Configuration
12 |
13 | A complete configuration file with comments can be found as [`albafetch.conf`](albafetch.conf) in this repository.
14 |
15 | ## Which file is used?
16 | Albafetch supports a series of configuration options that can be placed inside of a configuration file located in `$XDG_CONFIG_HOME/albafetch.conf` (`~/.config/albafetch.conf` is parsed if `XDG_CONFIG_HOME` is not set).
17 |
18 | Alternatively, if this file is not found, albafetch will look for `XDG_CONFIG_HOME/albafetch/albafetch.conf` (or `~/.config/albafetch/albafetch.conf`). This can be useful if you want to keep multiple configurations in the same folder.
19 |
20 | A custom file might be specified using the `--config` argument.
21 |
22 | ## Syntax
23 | The config should contain `entry = "value",` pairs (using quotation marks is mandatory). During parsing, albafetch will look for the first string matching the entry (which you can find in [the default config](albafetch.conf)), then locate the next quotation mark, check whether there is another quotation mark following it and if so take the value between the two.
24 |
25 | There are three different types of data that will be parsed:
26 | * Strings: No more than N bytes between the quotation marks will be read, but every single one of those bytes will be used.
27 | These variables will be marked in the example config with a `; str [N]` following the option.
28 | * Integers: An integer smaller or equal to N will be parsed using the C standard `atoi()` function (use `man 3 atoi` for specific information).
29 | The provided value will always be treaded as unsigned (using something like -1 will therefore be treated as 2³²-1, 4294967295)
30 | These variables will be marked in the example config with a `; int [N]` following the option.
31 | * Booleans: The program will recognize anything different from "false" as "true".
32 | These variables will be marked in the example config with a `; bool` following the option.
33 |
34 | All of this means that `AB"CboldDEF"whatever lol"wo"w` will be parsed the exact same way as `bold = "true",` or `bold""`, but I would not recommend this as it makes everything less readable. I might also stop supporting this at any moment, so the specified syntax is the only one that's guaranteed to work.
35 | I might also make the parser stricter in the future and configs written this way might stop working entirely.
36 |
37 | Also, any `~` that you may want to use will not get expanded to `/home/username` and will instead be parsed as it is. If you want to reference your home directory inside of this config file (e.g. to specify the path to a custom ascii art) you will have to do so manually.
38 |
39 | A specific option that's worth spending some extra time talking about is `ascii_art`. This option expects the path to a file that contains a custom logo. Its syntax is really straight-forward: You can specify up to 40 lines you want to use as logo (which can not be longer than 256 bytes long, including the closing null character. Note that Unicode characters will be bigger than 1B), and eventually a color on the first line. Anything that's not recognized as a color ("colors" are defined as black, red, green, yellow, blue, purple, cyan, gray or white) Will be considered the first line of the logo.
40 |
41 | This is what a logo file could look like:
42 | ```
43 | blue
44 | first_line
45 | second_line
46 | third_line
47 | fourth_line
48 | ```
49 |
50 | This file should **not** end with an empty line, and every logo line should be equally long (you can achieve this simply by adding spaces at the end of the shorter lines), or albafetch will have alignment problems. There is no way to add comments in this file, everything will be used as it is written (except some escape sequences, more about this further down).
51 |
52 | You can find an example logo file in this repository, more specifically [example_logo.txt](example_logo.txt).
53 |
54 | The config can also contain an ordered array of the modules that you want albafetch to print. The array has a vastly different syntax in the config, as shown here:
55 | ```
56 | modules = {
57 | "module1",
58 | "module2",
59 | "module3",
60 | }
61 | ```
62 | You can found a list of the accepted modules inside of [the default config](albafetch.conf). Any other value will be considered as plain text (and will be printed as-is, with no label nor dash).
63 |
64 | To parse this section, albafetch first locates a string matching `modules` in the config file, takes the part between the following curly braces, and reads the text between the following pairs of quotation marks.
65 | As for normal options, this allows some weird formats, like `modules{"module1""module2""module3"}`, but I also invite anyone to consider the parsing of similar strings undefined behavior.
66 |
67 | Anything that doesn't match what the parser is looking for will be ignored, but the usage of explicit comments is encouraged: whatever stands between a `;` or an `#` and the end of the line will not be read as part of the config. You can, however, still freely use `#` and `;` in your config, as they will **not** be considered when enclosed in a string (between a pair of `"`).
68 | There is currently no way to use multi-line comments.
69 |
70 | When albafetch parses a file (config or custom ascii art), it will also automatically unescape some escape sequences, like the following table shows:
71 | | File content | How it will be parsed |
72 | | --- | --- |
73 | | "\\e" | '\\033' (ANSI escape) |
74 | | "\\033" | '\\033' (ANSI escape) |
75 | | "\\n" | '\\n' (new line) |
76 | | "\\X" | 'X' (everything else) |
77 |
78 | Since it might be useful, here are some of the most useful ANSI escape sequences (you can find a more complete list [here](https://stackoverflow.com/a/33206814))
79 | | Function | Escape |
80 | | --- | --- |
81 | | Reset | `\e[0m` |
82 | | Bold | `\e[1m` |
83 | | Black | `\e[30m` |
84 | | Red | `\e[31m` |
85 | | Green | `\e[32m` |
86 | | Yellow | `\e[33m` |
87 | | Blue | `\e[34m` |
88 | | Purple | `\e[35m` |
89 | | Cyan | `\e[36m` |
90 | | White | `\e[97m` |
91 |
92 | Please note that these colors will be displayed as defined in the configuration of your terminal.
93 | You can check how a certain string will look using something like `echo -e "\e[1mHello, \e[31mWorld\e[0m"`.
94 | These escape sequences may be placed at any point inside of your config or custom ascii art and they *should* get parsed correctly (as long as you stay inside of the size limits defined for each field). You can even use multiple inside a single line.
95 |
96 | # Command-line arguments
97 | albafetch accepts a few command line arguments, which can be used to override certain values set in the config file.
98 |
99 | A short explanation of what every argument does, including every accepted and default value, can be obtained by running `albafetch --help`
100 |
101 | Here they are:
102 | * `--help` (or `-h`): Prints a small guide on the program usage and return RET_OK.
103 | * `--color` (or `-c`): Followed by the color you want to set, this option will override the config `default_color` entry and set a custom color for the whole output.
104 | * `--bold` (or `-b`): Followed by a boolean "on" or "off", this option overrides the config `bold` entry and enables or disables the usage of bold in the output.
105 | * `--logo` (or `-l`): This option, followed by the logo you want to print, overrides the config `logo` entry and makes albafetch print a custom logo instead of the default one.
106 | * `--align` (or `-a`): Followed by a boolean "on" or "off", this option overrides the config `align_infos` entry and enables of disables the alignment of the infos in the printed output.
107 | * `--ascii`: Followed by a valid file path, it lets you pick a file containing a custom ascii art that you'd like to use. When this option is used together with `--logo`, the latter has priority.
108 | * `--config`: Followed by a valid file path, this changes the config file that will be parsed to look for a valid configuration.
109 | * `--no-logo`: Using this will make albafetch not print a logo or ascii art (while still using it to get the color that should be printed).
110 | * `--no-config`: Using this will prevent any config file (provided using `--config` or the default one) from being used.
111 |
112 | # Return codes and errors
113 | | Return Code | Meaning |
114 | | --- | --- |
115 | | 0 | Correct execution |
116 | | 1 | Bad argument usage |
117 | | -1 | Bad environment |
118 |
119 | ## Return code 0
120 | As you probably already know, this is not an error, but it simply indicates that everything executed correctly. No need to worry.
121 |
122 | ## Error 1
123 | This is probably the result of a wrong usage of some command-line arguments. One or more error messages will be printed to stderr telling you exactly which argument(s) was used wrong.
124 |
125 | ## Error -1 (255)
126 | This error should only pop up if the program was not able to get the `HOME` environment variable, which should never happen. If you get this return code, you are probably experiencing worse than this dumb program not working.
127 |
128 | ---
129 |
130 | ###### © Aaron Blasko
131 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all compile clean run debug deb install uninstall
2 |
3 | OS := $(shell uname -o 2> /dev/null)
4 | KERNEL := $(shell uname -s 2> /dev/null)
5 |
6 | INSTALLPATH := /usr/local/bin
7 | CONFIGPATH := /etc/xdg
8 |
9 | INSTALLFLAGS := -Dm755
10 | CONFIGFLAGS := -Dm644
11 |
12 | ifeq ($(OS),Android)
13 | INSTALLPATH := $(PREFIX)/bin
14 | CONFIGPATH := $(PREFIX)/etc/xdg
15 | endif
16 |
17 | ifeq ($(KERNEL),Darwin)
18 | INSTALLFLAGS := -m755
19 | CONFIGFLAGS := -m644
20 | INSTALLPATH := /usr/local/bin
21 | CONFIGPATH := ~/.config/
22 | endif
23 |
24 | all: compile
25 |
26 | build:
27 | meson setup build
28 |
29 | clean:
30 | rm -rf build
31 |
32 | compile: build
33 | meson compile -C build albafetch
34 |
35 | run: compile
36 | build/albafetch
37 |
38 | debug: build
39 | meson compile -C build debug
40 | build/debug --no-pip
41 |
42 | deb: compile
43 | cd debian; \
44 | ./makedeb.sh
45 |
46 | install: compile
47 | mkdir -p $(INSTALLPATH) $(CONFIGPATH)
48 |
49 | install $(INSTALLFLAGS) build/albafetch $(INSTALLPATH)/albafetch
50 | install $(CONFIGFLAGS) albafetch.conf $(CONFIGPATH)/albafetch.conf
51 |
52 | uninstall:
53 | rm $(INSTALLPATH)/albafetch
54 | rm $(CONFIGPATH)/albafetch.conf
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # albafetch ~by alba4k
2 |
3 | #### Note: to prevent merge conflicts, please open your pull requests to the "development" branch, and check that one out before doing anything. Master is more stagnant and only updated when I know what I'm currently working on works as expected (most of the time).
4 |
5 | 
6 |
7 | albafetch is a simple and fast program to display a lot of system information in a neofetch-like layout in way less than a second. I decided to make this as a challenge for myself and since I found neofetch too slow (which is understandable given that we're talking about a 10k+ lines shell script).
8 |
9 |
10 |
11 | Preview
12 | This is what albafetch will likely look like by default:
13 |
14 | 
15 |
16 | And this is what [my configuration](https://github.com/alba4k/.dotfiles/blob/master/.config/albafetch/albafetch.conf) looks like
17 | 
18 |
19 |
20 |
21 | Here is a time comparison (exact execution times change between machines and runs):
22 |
23 |
24 | Time comparison
25 |
26 | 
27 | 
28 |
29 |
30 |
31 | You will find a lot of useful usage and configuration related info inside of the [user manual](MANUAL.md) and a small list of the things I changed since the last release in the [changelog](CHANGELOG.md).
32 |
33 | It currently supports a lot of GNU/Linux distributions, macOS (both x64 and arm64 macs) and even Android (only tested in Termux).
34 | Feel free to test any other platform :)
35 |
36 | ## Table of contents
37 | 1. [Dependencies](#dependencies)
38 | * [For building](#build-dependencies)
39 | * [At runtime](#runtime-dependencies)
40 | 2. [Compilation](#compilation)
41 | * [make](#using-the-makefile)
42 | * [meson](#using-meson)
43 | * [nix](#using-nix)
44 | 3. [Installation](#installation)
45 | * [Arch BTW](#for-arch-linux)
46 | * [NixOS](#for-nixos)
47 | * [MacPorts](#for-older-macos-versions)
48 | * [Manually](#manual-installation)
49 | 4. [Configuration](#configuration)
50 | > [example config](albafetch.conf)
51 | 5. [Contributing](#contributing)
52 |
53 | # Dependencies
54 |
55 | ## Build dependencies
56 | These will usually also install the relative [runtime dependencies](#runtime-dependencies)
57 | Dependencies marked with an asterisk are optional. This means that if not installed at compile-time, albafetch will be compiles with custom implementations of the functions used.
58 |
59 | * [libpci](https://github.com/pciutils/pciutils)\*:
60 | Used to get gpu information
61 | - On Arch Linux, [pciutils](https://archlinux.org/packages/core/x86_64/pciutils)
62 | - On Debian, [libpci-dev](https://packages.debian.org/bookworm/libpci-dev)
63 | - On Fedora, [pciutils-devel](https://packages.fedoraproject.org/pkgs/pciutils/pciutils-devel)
64 | - On Alpine Linux, [pciutils-dev](https://pkgs.alpinelinux.org/package/edge/main/x86_64/pciutils-dev)
65 | * [sqlite3](https://www.sqlite.org):
66 | Used to gather the amount of installed rpm packages
67 | - On Arch Linux, [sqlite](https://archlinux.org/packages/core/x86_64/sqlite)
68 | - On Debian, [libsqlite3-dev](https://packages.debian.org/bookworm/libsqlite3-dev)
69 | - On Fedora, [sqlite-devel](https://packages.fedoraproject.org/pkgs/sqlite/sqlite-devel)
70 | - On Alpine Linux, [sqlite-dev](https://pkgs.alpinelinux.org/package/edge/main/x86_64/sqlite-dev)
71 | * [libc](https://www.gnu.org/software/libc) (likely already installed):
72 | - On Alpine Linux, [musl-dev](https://pkgs.alpinelinux.org/package/edge/main/x86_64/musl-dev)
73 | * [glib](https://docs.gtk.org/glib/)\*:
74 | Provides some useful abstractions
75 | - On Arch Linux, [glib2]((https://archlinux.org/packages/core/x86_64/glib2))
76 | - On Debian, [libglib2.0-dev](https://packages.debian.org/bookworm/libglib2.0)
77 | - On Fedora, [glib2-devel](https://packages.fedoraproject.org/pkgs/glib2/glib2-devel)
78 | - On Alpine Linux, [glib-dev](https://pkgs.alpinelinux.org/package/edge/main/x86/glib)
79 | * [git](https://git-scm.com)\*:
80 | When building from this repo, used to add the commit hash in the `--version` output
81 | * A build system:
82 | To build the project
83 | - A [Makefile](https://www.gnu.org/software/make) exists (which uses [meson](https://mesonbuild.com/Getting-meson.html), [ninja](https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages) and [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config)/[pkgconf](http://pkgconf.org)), more details are found [here](#compilation).
84 |
85 | ## Runtime dependencies
86 | I would like to eventually remove those, by checking at runtime if they are installed and not use them if not so.
87 | Dependencies marked with an asterisk are optional. This means that if not installed at compile-time, albafetch will be compiles with custom implementations of the functions used. If the binary was compiled with the dependency installed, however, it will be needed at runtime too.
88 |
89 | * [libpci](https://github.com/pciutils/pciutils)\*:
90 | - On Arch Linux, [pciutils](https://archlinux.org/packages/core/x86_64/pciutils)
91 | - On Debian, [libpci3](https://packages.debian.org/buster/libpci3)
92 | - On Fedora, [pciutils-libs](https://packages.fedoraproject.org/pkgs/pciutils/pciutils-libs)
93 | - On Alpine Linux, [pciutils-dev](https://pkgs.alpinelinux.org/package/edge/main/x86_64/pciutils)
94 | * [sqlite3](https://www.sqlite.org):
95 | - On Arch Linux, [sqlite](https://archlinux.org/packages/core/x86_64/sqlite/)
96 | - On Debian, [sqlite3](https://packages.debian.org/bookworm/sqlite3)
97 | - On Fedora, [sqlite](https://packages.fedoraproject.org/pkgs/sqlite/sqlite)
98 | - On Alpine Linux, [sqlite](https://pkgs.alpinelinux.org/package/edge/main/x86_64/sqlite)
99 | * [glib](https://docs.gtk.org/glib/)\*:
100 | - On Arch Linux, [glib2]((https://archlinux.org/packages/core/x86_64/glib2))
101 | - On Debian, [libglib2.0-dev](https://packages.debian.org/bookworm/libglib2.0)
102 | - On Fedora, [glib2-devel](https://packages.fedoraproject.org/pkgs/glib2/glib2)
103 | - On Alpine Linux, [glib-dev](https://pkgs.alpinelinux.org/package/edge/main/x86/glib)
104 | * there must be a `sh` binary in your PATH. This should already be satisfied on any UNIX-like system
105 |
106 | # Compilation
107 |
108 | ## Using the Makefile
109 |
110 | This will need you to have a C compiler installed and will still use meson/ninja under the hood.
111 |
112 | ```shell
113 | $ git clone https://github.com/alba4k/albafetch
114 | $ cd albafetch
115 | $ make
116 | ```
117 |
118 | ## Using meson
119 |
120 | If you prefer to build with meson/ninja directly, you can use these commands:
121 |
122 | ```sh
123 | $ git clone https://github.com/alba4k/albafetch
124 | $ cd albafetch
125 | $ meson setup build
126 | $ meson compile -C build
127 | ```
128 |
129 | In both cases, an executable file should appear as `build/albafetch` if the compilation succeeds.
130 |
131 | ### Debug builds
132 | It is possible to build a debug binary (`build/debug`) that will test every single function and make sure it runs correctly. This can be done by running
133 |
134 | ```sh
135 | $ make debug
136 | ```
137 |
138 | ## Using meson
139 |
140 | If you prefer to build with meson/ninja directly, you can use these commands:
141 |
142 | ```sh
143 | $ meson setup build
144 | $ meson compile -C build
145 | $ build/debug
146 | ```
147 |
148 | ## Using nix
149 |
150 | Building with nix can make compiling in some ways much easier, such as when compiling statically
151 | or cross compiling. A few convenience outputs are included:
152 |
153 | ```sh
154 | nix build .#albafetch # regular, dynamically linked build
155 | nix build .#albafetch-static # statically linked build (only available on linux)
156 | nix build .#albafetch-arm # cross compiling from x86_64 to arm (only available on x86_64)
157 | ```
158 |
159 | # Installation
160 |
161 | ## For Arch Linux
162 | An AUR package is available, [albafetch-git](https://aur.archlinux.org/packages/albafetch-git).
163 | There are three packages on the AUR that provide albafetch:
164 | * [albafetch](https://aur.archlinux.org/packages/albafetch-) will compile the source code of the latest release
165 | * [albafetch-bin](https://aur.archlinux.org/packages/albafetch-bin) will install a pre-compiled binary from the latest release
166 | * [albafetch-git](https://aur.archlinux.org/packages/albafetch-git) will compile the source of the latest commit in master
167 |
168 | You can find more information on how to install packages from the AUR in the [Arch Wiki](https://wiki.archlinux.org/title/Arch_User_Repository#Installing_and_upgrading_packages)
169 |
170 | ## For Debian
171 | You can create a DEB package from the repo itself
172 |
173 | This can be done via a guided procedure
174 |
175 | ```
176 | $ git clone https://github.com/alba4k/albafetch
177 | $ cd albafetch
178 |
179 | $ make deb
180 | ```
181 |
182 | This will create a deb package for you and ask if you want to install it.
183 |
184 | ## For NixOS
185 |
186 | `nix profile`:
187 |
188 | ```sh
189 | $ nix profile install .#albafetch
190 | ```
191 |
192 | `nix-env`:
193 |
194 | ```sh
195 | $ nix-env -iA packages..albafetch # platform examples: x86_64-linux, aarch64-linux, aarch64-darwin
196 | ```
197 |
198 | Using the overlay (Flake):
199 |
200 | ```nix
201 | {
202 | inputs = {
203 | nixpkgs.url = "nixpkgs/nixos-unstable";
204 | albafetch = {
205 | url = "github:alba4k/albafetch";
206 | inputs.nixpkgs.follows = "nixpkgs";
207 | };
208 | };
209 |
210 | outputs = {nixpkgs, albafetch, ...}: {
211 | nixosConfigurations.host = nixpkgs.lib.nixosSystem {
212 | system = "x86_64-linux";
213 | modules = [
214 | ./configuration.nix
215 | {
216 | nixpkgs.overlays = [albafetch.overlays.default];
217 | environment.systemPackages = [pkgs.albafetch];
218 | }
219 | ];
220 | };
221 | };
222 | }
223 | ```
224 |
225 | Using the overlay (`builtins.fetchTarball`):
226 |
227 | ```nix
228 | {pkgs, ...}: {
229 | nixpkgs.overlays = [(import (builtins.fetchTarball "https://github.com/alba4k/albafetch/master.tar.gz")).overlays.default];
230 | environment.systemPackages = with pkgs; [
231 | albafetch
232 | ];
233 | }
234 | ```
235 |
236 | ## For older macOS versions
237 |
238 | On older macOS (~11 and lower) versions, albafetch likely won't build natively.
239 |
240 | You can, however, install albafetch on those using the [package](https://ports.macports.org/port/albafetch) on MacPorts
241 |
242 | This can be easily done with the following
243 | ```
244 | # port install albafetch
245 | ```
246 |
247 | ## Manual installation
248 |
249 | What if your OS is not included in the ones mentioned?
250 | In this case, you can either compile the source code yourself and install albafetch manually, or you can grab an executable from the [latest release](https://github.com/alba4k/albafetch/releases/latest).
251 |
252 | Please note that albafetch currently won't run on Windows (despite `albafetch --logo windows` being an option), but I'm planning to eventually add support (sooner or later). Feel free to help :)
253 |
254 | ```
255 | $ git clone https://github.com/alba4k/albafetch
256 | $ cd albafetch
257 |
258 | $ make
259 | # make install
260 | ```
261 |
262 | `make install` needs elevated privileges on Linux (e.g. `sudo` or a root shell) to write to `/usr/bin`, while `/usr/local/bin` can be accessed as a normal user *on macOS*.
263 |
264 | Alternatively, you may prefer meson to perform the installation:
265 |
266 | ```
267 | $ git clone https://github.com/alba4k/albafetch
268 | $ cd albafetch
269 | $ meson setup build
270 | $ meson compile -C build
271 | $ meson install -C build
272 | ```
273 |
274 | Meson will install the executable to `/usr/local/bin`, which you may or may not want (executables in this directory are ran instead of ones in `/usr/bin`).
275 |
276 | # Configuration
277 |
278 | albafetch can be customized using a config file, usually `~/.config/albafetch.conf` for your user or `/etc/xdg/albafetch.conf`.
279 |
280 | You can find an example configuration file (which only provides the default values of every option) [here](albafetch.conf).
281 | Although this file includes some short comments on how the various options work, I highly recommend checking out the [user manual](MANUAL.md) for a deeper understanding of the way this config file works.
282 |
283 | # Contributing
284 |
285 | Almost everything included in this program is written in C.
286 |
287 | If you want to, you can directly modify the source code contained in this repository and recompile the program afterwards to get some features you might want or need.
288 |
289 | New logos can be added in [`src/logos.h`](src/logos.h) (be careful to follow the format), new infos in `src/info` and [`src/info/info.h`](src/info/info.h). Config options are mainly parsed in [`src/utils.c`](src/utils.c). You will also need to edit [`src/main.c`](src/main.c) afterwards to fully enable the new features.
290 |
291 | Don't mind opening a pull request if you think some of the changes you made should be in the public version. Please run `clang-tidy --fix src/**/*{.c,.h}` to check for any issues and `clang-format -i src/**/*{c,h}` to make sure the code style is consistent with the rest of the project before committing.
292 |
293 | Any contribution, even just a fix of a typo, is highly appreciated.
294 |
295 | ---
296 |
297 | ###### © Aaron Blasko
298 |
299 | ###### Initially started in March 2022
300 |
--------------------------------------------------------------------------------
/albafetch.conf:
--------------------------------------------------------------------------------
1 | # Check https://github.com/alba4k/albafetch/blob/master/MANUAL.md for additional info.
2 |
3 | # My (the authors) personal configuration can be found here:
4 | # https://github.com/alba4k/.dotfiles/blob/master/.config/albafetch/albafetch.conf
5 |
6 | # CONFIGURATION OPTIONS:
7 |
8 | # align all the infos
9 | align_infos = "false" ; bool
10 |
11 | # should bold be used?
12 | bold = "true" ; bool
13 |
14 | # you can provide a file containing a logo to use
15 | # the normal logo is used when not set
16 | ; ascii_art = "/path/to/example_logo.txt" ; str[96]
17 |
18 | # which logo should always be printed?
19 | # OS default is used when not set
20 | ; logo = "linux" ; str [24]
21 |
22 | # what color should be used?
23 | # the color of the logo is used when not set
24 | ; default_color = "green" ; str [8]
25 |
26 | # the little separator used between each module label and content
27 | dash = ": " ; str [16]
28 |
29 | # lenght of the spacing between the logo and the modules
30 | spacing = "5" ; int [64]
31 |
32 |
33 | # LAYOUT
34 |
35 | # this contains an ordered array of the modules that should be printed.
36 | # every unrecognized value will be printed as-is
37 | modules = {
38 | # here is the default order:
39 | "title", # title in the format user@hostname
40 | "separator", # separator between two lines
41 | "uptime", # current uptime
42 | "separator", # --------------
43 | "os", # operating system
44 | "kernel", # kernel version
45 | "desktop", # desktop environnment
46 | "shell", # shell (parent process, actually)
47 | "term", # terminal
48 | "packages", # number of installed packages
49 | "separator", # ----------------------------
50 | "host", # OEM device / motherboard model name
51 | "cpu", # CPU
52 | "gpu", # GPU
53 | "memory", # used and total RAM
54 | "space", # empty line
55 | "colors", # terminal colors
56 | "light_colors", # terminal colors (light versions)
57 | # there are also some other modules, disabled by default
58 | ; "user", # username
59 | ; "hostname", # hostname
60 | ; "gtk_theme" # gtk_theme
61 | ; "icon_theme" # icon_theme
62 | ; "cursor_theme" # cursor_theme
63 | ; "login_shell", # login shell
64 | ; "bios", # BIOS version (Linux only)
65 | ; "public_ip", # public IP adress
66 | ; "local_ip", # local IP adress
67 | ; "pwd", # current working directory
68 | ; "date", # date and time
69 | ; "battery", # battery percentage and status (Linux only)
70 | ; "swap", # swap usage and percentage (Linux only)
71 | }
72 |
73 | # MODULE-SPECIFIC OPTIONS:
74 |
75 | # Separators
76 | # the prefix printed before a separator
77 | separator_prefix = "" ; str [64]
78 | # the character used in separators
79 | separator_character = "-" ; str [8]
80 |
81 | # Spacings
82 | # the prefix printed before a spacing
83 | spacing_prefix = "" ; str [64]
84 |
85 | # Title (user@host)
86 | # the prefix printed before the title
87 | title_prefix = "" ; str [64]
88 | # defines whether the title should be colored
89 | colored_title = "true" ; bool
90 |
91 | # User
92 | # the prefix printed before the user
93 | user_prefix = "User" ; str [64]
94 |
95 | # Hostname
96 | # the prefix printed before the hostnmae
97 | hostname_prefix = "Hostname" ; str [64]
98 |
99 | # Current Uptime
100 | # the prefix printed before the uptime
101 | uptime_prefix = "Uptime" ; str [64]
102 |
103 | # Operating System
104 | # the prefix printed before the OS
105 | os_prefix = "OS" ; str [64]
106 | # whether the architecture should be printed
107 | os_arch = "true" ; bool
108 |
109 | # Kernel Version
110 | # the prefix printed before the kernel
111 | kernel_prefix = "Kernel" ; str [64]
112 | # whether the kernel version should be printed in a shorter form
113 | kernel_short = "false" ; bool
114 | # prints the kernel type (useful when using kernel_short)
115 | kernel_type = "false"
116 |
117 | # Desktop Environnment
118 | # the prefix printed before the desktop
119 | desktop_prefix = "Desktop" ; str [64]
120 | # whether the desktop type should be printed (X11 / Wayland)
121 | desktop_type = "true" ; bool
122 |
123 | # GTK Theme
124 | # the prefix printed before the theme name
125 | gtk_theme_prefix = "Theme" ; str [64]
126 |
127 | # Icon Theme
128 | # the prefix printed before the theme name
129 | icon_theme_prefix = "Icons" ; str [64]
130 |
131 | # Cursor Theme
132 | # the prefix printed before the theme name
133 | cursor_theme_prefix = "Cursor" ; str [64]
134 |
135 | # Shells
136 | # the prefix printed before the shell
137 | shell_prefix = "Shell" ; str [64]
138 | # the prefix printed before the login shell
139 | login_shell_prefix = "Login" ; str [64]
140 | # whether the full shell path should be printed
141 | shell_path = "false" ; bool
142 |
143 | # Terminal
144 | # the prefix printed before the terminal
145 | term_prefix = "Terminal" ; str [64]
146 | # whether the current session is running via ssh
147 | term_ssh = "true" ; bool
148 |
149 | # Installed Packages
150 | # the prefix printed before the numebr of packages
151 | pkg_prefix = "Packages" ; str [64]
152 | # whether the source of the individual packages should be printed
153 | pkg_mgr = "true" ; bool
154 | # whether the amount of packages installed
155 | # from a specific source should be printed
156 | pkg_pacman = "true" ; bool
157 | pkg_dpkg = "true" ; bool
158 | pkg_flatpak = "true" ; bool
159 | pkg_snap = "true" ; bool
160 | pkg_brew = "true" ; bool
161 | pkg_pip = "false" ; bool
162 |
163 | # Host System
164 | # the prefix printed before the host
165 | host_prefix = "Host" ; str [64]
166 |
167 | # BIOS Version
168 | # the prefix printed before the BIOS
169 | bios_prefix = "BIOS" ; str [64]
170 |
171 | # Processor
172 | # the prefix printed before the cpu
173 | cpu_prefix = "CPU" ; str [64]
174 | # whether the manufacturer should be printed
175 | cpu_brand = "true" ; bool
176 | # whether the frequency should be printed
177 | cpu_freq = "true" ; bool
178 | # whether the amount of threads should be printed
179 | cpu_count = "true" ; bool
180 |
181 | # Graphics card
182 | # the prefix printed before the gpu
183 | gpu_prefix = "GPU" ; str [64]
184 | # whether the manufacturer should be printed
185 | gpu_brand = "true" ; bool
186 | # the specific GPU that should be printed (0 for all, otherwise the specific number 1-3)
187 | gpu_index = "0" ; int [3]
188 |
189 | # Memory
190 | # the prefix printed before the ram
191 | mem_prefix = "Memory" ; str [64]
192 | # whether the percentage of used memory should be printed
193 | mem_perc = "true" ; bool
194 |
195 | # Swap
196 | # the prefix printed before the swap
197 | swap_prefix = "Swap" ; str [64]
198 | # whether the percentage of used swap should be printed
199 | swap_perc = "true" ; bool
200 |
201 | # IPs
202 | # the prefix printed before the public IP
203 | pub_prefix = "Public IP" ; str [64]
204 | # the prefix printed before the local IPs
205 | loc_prefix = "Local IP" ; str [64]
206 | # whether the localhost should be shown as local IP
207 | loc_localhost = "false" ; bool
208 | # whether docker should be shown as local IP
209 | loc_docker = "false" ; bool
210 |
211 | # Current working directory
212 | # the prefix printed before the path
213 | pwd_prefix = "Directory" ; str [64]
214 | # whether the full path should be printed
215 | pwd_path = "true" ; bool
216 |
217 | # Current date
218 | # the prefix printed before the date
219 | date_prefix = "Date" ; str [64]
220 | # the format the date is printed in (don't change the %02d parts)
221 | date_format = "%02d/%02d/%d %02d:%02d:%02d" ; str [32]
222 |
223 | # Battery
224 | # the prefix printed before the battery info
225 | bat_prefix = "Battery" ; str [64]
226 | # whether the battery status should be printed
227 | bat_status = "true" ; bool
228 |
229 |
230 | # Terminal Colors
231 | # the prefix printed before the colors
232 | colors_prefix = "" ; str [64]
233 | # the prefix printed before the light colors
234 | colors_light_prefix = "" ; str [64]
235 | # the string that will be colored
236 | col_block_str = " " ; str [24]
237 | # should the foreground get colored, instead of the background?
238 | col_background = "true" ; bool
239 |
--------------------------------------------------------------------------------
/debian/makedeb.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | version=$(../build/albafetch --version | cut -d " " -f 1)
4 | arch=$(uname -m)
5 |
6 | if [ "$arch" = "x86_64" ]; then
7 | arch="amd64"
8 | elif [ "$arch" = "aarch64" ]; then
9 | arch="arm64"
10 | else
11 | arch="any"
12 | fi
13 |
14 | echo -e "\n\e[1m[\e[33mINFO\e[0m\e[1m]\e[0m Detected version $version"
15 | echo -e "\e[1m[\e[33mINFO\e[0m\e[1m]\e[0m Detected architecture $arch\n"
16 |
17 | dirname="albafetch_"$version"_"$arch
18 |
19 | mkdir -p "$dirname/DEBIAN"
20 |
21 | install -Dm 755 "../build/albafetch" "$dirname/usr/bin/albafetch"
22 |
23 | install -Dm 644 "../albafetch.conf" "$dirname/etc/xdg/albafetch.conf"
24 | install -Dm 644 "../LICENSE" "$dirname/usr/share/licences/albafetch/LICENSE"
25 | install -Dm 644 "../README.md" "$dirname/usr/share/doc/albafetch/README.md"
26 | install -Dm 644 "../MANUAL.md" "$dirname/usr/share/doc/albafetch/MANUAL.md"
27 |
28 | echo "Package: albafetch
29 | Version: $version
30 | Architecture: $arch
31 | Essential: no
32 | Priority: optional
33 | Depends: libpci3
34 | Maintainer: Aaron Blasko
35 | Description: Faster neofetch alternative, written in C." > "$dirname"/DEBIAN/control
36 |
37 | dpkg-deb --build "$dirname"
38 |
39 | echo -e -n "\n\e[1m\e[32mInstall Now\e[0m\e[1m [Y/n] ?\e[0m > "
40 | read -r -n 1 install
41 |
42 | if [ "$install" = "N" ] || [ "$install" = "n" ]; then
43 | echo -e "\n\e[1m[\e[32mDONE\e[0m\e[1m]\e[0m File created as $PWD/$dirname.deb"
44 | else
45 | sudo dpkg -i "$dirname.deb"
46 | fi
--------------------------------------------------------------------------------
/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs ? import {
3 | inherit system;
4 | config = { };
5 | overlays = [ ];
6 | },
7 | system ? builtins.currentSystem,
8 | }:
9 |
10 | {
11 | albafetch = pkgs.callPackage ./nix/package.nix { };
12 | }
13 |
--------------------------------------------------------------------------------
/example_logo.txt:
--------------------------------------------------------------------------------
1 | blue
2 | ███ █ ███
3 | █ █ █ █ █
4 | ███ █ ███
5 | █ █ █ █ █
6 | █ █ ███ ███
7 |
8 | ███ ███ ███
9 | █ █ █ █
10 | ███ ██ ██
11 | █ █ █ █
12 | █ █ █ ███
13 |
14 | ███ ███ █ █
15 | █ █ █ █
16 | █ █ ███
17 | █ █ █ █
18 | █ ███ █ █
19 |
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "flake-utils": {
4 | "inputs": {
5 | "systems": "systems"
6 | },
7 | "locked": {
8 | "lastModified": 1731533236,
9 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
10 | "owner": "numtide",
11 | "repo": "flake-utils",
12 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
13 | "type": "github"
14 | },
15 | "original": {
16 | "owner": "numtide",
17 | "repo": "flake-utils",
18 | "type": "github"
19 | }
20 | },
21 | "nixpkgs": {
22 | "locked": {
23 | "lastModified": 1748460289,
24 | "narHash": "sha256-7doLyJBzCllvqX4gszYtmZUToxKvMUrg45EUWaUYmBg=",
25 | "owner": "NixOS",
26 | "repo": "nixpkgs",
27 | "rev": "96ec055edbe5ee227f28cdbc3f1ddf1df5965102",
28 | "type": "github"
29 | },
30 | "original": {
31 | "id": "nixpkgs",
32 | "ref": "nixos-unstable",
33 | "type": "indirect"
34 | }
35 | },
36 | "root": {
37 | "inputs": {
38 | "flake-utils": "flake-utils",
39 | "nixpkgs": "nixpkgs"
40 | }
41 | },
42 | "systems": {
43 | "locked": {
44 | "lastModified": 1681028828,
45 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
46 | "owner": "nix-systems",
47 | "repo": "default",
48 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
49 | "type": "github"
50 | },
51 | "original": {
52 | "owner": "nix-systems",
53 | "repo": "default",
54 | "type": "github"
55 | }
56 | }
57 | },
58 | "root": "root",
59 | "version": 7
60 | }
61 |
--------------------------------------------------------------------------------
/flake.nix:
--------------------------------------------------------------------------------
1 | {
2 | description = "Faster neofetch alternative, written in C";
3 |
4 | nixConfig = {
5 | extra-substituters = [ "https://albafetch.cachix.org" ];
6 | extra-trusted-public-keys = [
7 | "albafetch.cachix.org-1:wTFl2hoUXiYlzUp/XA/bfZTP5KqZTToyq0+sfIVseUU="
8 | ];
9 | };
10 |
11 | inputs = {
12 | nixpkgs.url = "nixpkgs/nixos-unstable";
13 | flake-utils.url = "github:numtide/flake-utils";
14 | };
15 |
16 | outputs =
17 | {
18 | self,
19 | nixpkgs,
20 | flake-utils,
21 | }:
22 |
23 | flake-utils.lib.eachDefaultSystem (
24 | system:
25 |
26 | let
27 | inherit (nixpkgs) lib;
28 | pkgs = nixpkgs.legacyPackages.${system};
29 |
30 | callWith = pkgs: (lib.makeScope pkgs.newScope (lib.flip self.overlays.default pkgs)).albafetch;
31 |
32 | armPkgs = pkgs.pkgsCross.aarch64-multiplatform;
33 | albafetch-static = callWith pkgs.pkgsStatic;
34 | in
35 |
36 | {
37 | devShells.default = pkgs.mkShell {
38 | inputsFrom = [ self.packages.${system}.albafetch ];
39 | };
40 |
41 | formatter = pkgs.alejandra;
42 |
43 | packages = {
44 | albafetch = callWith pkgs;
45 | default = self.packages.${system}.albafetch;
46 | };
47 |
48 | legacyPackages =
49 | {
50 | x86_64-linux = {
51 | albafetch-arm = callWith armPkgs.pkgsStatic;
52 | inherit albafetch-static;
53 | };
54 |
55 | aarch64-linux = { inherit albafetch-static; };
56 |
57 | x86_64-darwin = {
58 | albafetch-arm = callWith armPkgs;
59 | };
60 | }
61 | .${system} or { };
62 | }
63 | )
64 | // {
65 | overlays.default = final: _: {
66 | albafetch = final.callPackage ./nix/package.nix { inherit self; };
67 | };
68 | };
69 | }
70 |
--------------------------------------------------------------------------------
/images/albafetch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alba4k/albafetch/575fcee1ae5cb8d30f06e0af9275fcdc8d1e5ba6/images/albafetch.png
--------------------------------------------------------------------------------
/images/albafetch_demo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alba4k/albafetch/575fcee1ae5cb8d30f06e0af9275fcdc8d1e5ba6/images/albafetch_demo.png
--------------------------------------------------------------------------------
/images/albafetch_demo_default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alba4k/albafetch/575fcee1ae5cb8d30f06e0af9275fcdc8d1e5ba6/images/albafetch_demo_default.png
--------------------------------------------------------------------------------
/images/time_albafetch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alba4k/albafetch/575fcee1ae5cb8d30f06e0af9275fcdc8d1e5ba6/images/time_albafetch.png
--------------------------------------------------------------------------------
/images/time_neofetch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alba4k/albafetch/575fcee1ae5cb8d30f06e0af9275fcdc8d1e5ba6/images/time_neofetch.png
--------------------------------------------------------------------------------
/images/v2.0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alba4k/albafetch/575fcee1ae5cb8d30f06e0af9275fcdc8d1e5ba6/images/v2.0.png
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project(
2 | 'albafetch',
3 | 'c',
4 | version : '4.2.1',
5 | default_options : ['warning_level=3'],
6 | license : 'MIT',
7 | meson_version: '>=1.3.0'
8 | )
9 |
10 | src = [
11 | 'src/config/config.c',
12 | 'src/config/parsing.c',
13 | 'src/info/battery.c',
14 | 'src/info/bios.c',
15 | 'src/info/colors.c',
16 | 'src/info/cpu.c',
17 | 'src/info/cursor_theme.c',
18 | 'src/info/date.c',
19 | 'src/info/desktop.c',
20 | 'src/info/gpu.c',
21 | 'src/info/gtk_theme.c',
22 | 'src/info/host.c',
23 | 'src/info/hostname.c',
24 | 'src/info/icon_theme.c',
25 | 'src/info/info.h',
26 | 'src/info/kernel.c',
27 | 'src/info/light_colors.c',
28 | 'src/info/local_ip.c',
29 | 'src/info/login_shell.c',
30 | 'src/info/memory.c',
31 | 'src/info/os.c',
32 | 'src/info/packages.c',
33 | 'src/info/public_ip.c',
34 | 'src/info/pwd.c',
35 | 'src/info/shell.c',
36 | 'src/info/swap.c',
37 | 'src/info/term.c',
38 | 'src/info/uptime.c',
39 | 'src/info/user.c',
40 | 'src/optdeps/glib.c',
41 | 'src/optdeps/libpci.c',
42 | 'src/utils/queue.c',
43 | 'src/utils/utils.c',
44 | 'src/utils/wrappers.c',
45 | ]
46 |
47 | build_args = [
48 | '-Wall',
49 | '-Wextra',
50 | '-O3',
51 | '-ffast-math',
52 | '-std=gnu99',
53 | ]
54 |
55 | # DEPENDENCY HANDLING
56 |
57 | project_dependencies = []
58 |
59 | glib = dependency('glib-2.0', required: false)
60 | if glib.found()
61 | build_args += '-DGLIB_EXISTS'
62 | project_dependencies += glib
63 | endif
64 |
65 | if host_machine.system() == 'linux'
66 | project_dependencies += dependency('sqlite3', required: true)
67 |
68 | libpci = dependency('libpci', required: false)
69 | if libpci.found()
70 | build_args += '-DLIBPCI_EXISTS'
71 | project_dependencies += libpci
72 | endif
73 | elif host_machine.system() == 'darwin'
74 | project_dependencies += dependency('appleframeworks', modules : ['Foundation', 'IOKit'], required: true)
75 | add_languages('objc')
76 | src += [
77 | 'src/macos/macos_infos.c',
78 | 'src/macos/bsdwrap.c',
79 | 'src/macos/macos_gpu_string.m',
80 | ]
81 | endif
82 |
83 | # MAKE THE VERSION PRINTED BY albafetch -h DYNAMIC
84 | git = find_program('git', required : false)
85 | commit = '{unknown}'
86 | if git.found()
87 | commit_cmd = run_command(git, 'rev-parse', '--short', 'HEAD', check: false)
88 | if commit_cmd.returncode() == 0
89 | commit = commit_cmd.stdout().strip()
90 | endif
91 | endif
92 |
93 | config = configuration_data()
94 | config.set('VERSION', '"'+meson.project_version()+'"')
95 | config.set('COMMIT', '"'+commit+'"')
96 | configure_file(configuration: config, output: 'version.h')
97 | build_args += '-DHAVE_VERSION_H'
98 |
99 | # BUILD
100 |
101 | src_debug = src + ['src/debug.c']
102 | src += 'src/main.c'
103 |
104 | debug_args = build_args + ['-g']
105 |
106 | executable(
107 | meson.project_name(),
108 | src,
109 | dependencies : project_dependencies,
110 | install : true,
111 | c_args : build_args,
112 | include_directories: include_directories('.')
113 | )
114 |
115 | executable(
116 | 'debug',
117 | src_debug,
118 | dependencies : project_dependencies,
119 | install : false,
120 | c_args : debug_args,
121 | include_directories: include_directories('.')
122 | )
123 |
--------------------------------------------------------------------------------
/nix/package.nix:
--------------------------------------------------------------------------------
1 | {
2 | lib,
3 | stdenv,
4 | apple-sdk_12,
5 | meson,
6 | ninja,
7 | pciutils,
8 | pkg-config,
9 | sqlite,
10 |
11 | self ? { },
12 | }:
13 |
14 | let
15 | latestTag = "4.2.1";
16 |
17 | fullDate = lib.substring 0 8 self.lastModifiedDate;
18 |
19 | formattedDate =
20 | if (self ? "lastModifiedDate") then
21 | lib.concatStringsSep "-" [
22 | # YYYY
23 | (lib.substring 0 4 fullDate)
24 | ## MM
25 | (lib.substring 4 2 fullDate)
26 | # DD
27 | (lib.substring 6 2 fullDate)
28 | ]
29 | else
30 | "unknown";
31 | in
32 |
33 | stdenv.mkDerivation {
34 | name = "albafetch";
35 | version = "${latestTag}-unstable-${formattedDate}";
36 |
37 | src = self;
38 |
39 | buildInputs =
40 | [
41 | sqlite
42 | ]
43 | ++ lib.optional stdenv.hostPlatform.isDarwin apple-sdk_12
44 | ++ lib.optional stdenv.hostPlatform.isLinux pciutils;
45 |
46 | nativeBuildInputs = [
47 | meson
48 | ninja
49 | pkg-config
50 | ];
51 |
52 | OBJC = lib.optionalString stdenv.hostPlatform.isDarwin "clang";
53 |
54 | postFixup = lib.optionalString stdenv.hostPlatform.isStatic ''
55 | rm -r $out/nix-support
56 | '';
57 |
58 | meta = {
59 | description = "Faster neofetch alternative, written in C.";
60 | homepage = "https://github.com/alba4k/albafetch";
61 | license = lib.licenses.mit;
62 | maintainers = with lib.maintainers; [ getchoo ];
63 | platforms = lib.platforms.unix;
64 | };
65 | }
66 |
--------------------------------------------------------------------------------
/src/config/config.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 | #include "parsing.h"
3 | #include "../utils/logos.h"
4 | #include "../utils/return.h"
5 | #include "../utils/utils.h"
6 |
7 | #define GNU_SOURCE
8 |
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 | // a return code of 0 means that the option was parsed successfully
16 | int parseConfigStr(const char *source, const char *field, char *dest, const size_t maxlen) {
17 | char *ptr, *end;
18 |
19 | // looks for the keyword
20 | ptr = strstr(source, field);
21 | if(ptr == NULL)
22 | return ERR_PARSING;
23 |
24 | // looks for the opening "
25 | ptr = strchr(ptr, '"');
26 | if(ptr == NULL)
27 | return ERR_PARSING;
28 |
29 | // checks whether the string continues after
30 | ++ptr;
31 | if(*ptr == 0)
32 | return ERR_PARSING;
33 |
34 | // looks for the closing "
35 | end = strchr(ptr, '"');
36 | if(end == NULL)
37 | return ERR_PARSING;
38 |
39 | // copies the option
40 | *end = 0;
41 |
42 | size_t len = strlen(ptr);
43 | if(len + 1 > maxlen) {
44 | memcpy(dest, ptr, maxlen);
45 | dest[maxlen - 1] = 0;
46 | } else
47 | memcpy(dest, ptr, len + 1);
48 |
49 | *end = '"';
50 |
51 | return RET_OK;
52 | }
53 |
54 | // a return code of 0 means that the option was parsed successfully
55 | int parseConfigInt(const char *source, const char *field, int *dest, const unsigned max) {
56 | char *ptr, *end;
57 |
58 | // looks for the keyword
59 | ptr = strstr(source, field);
60 | if(ptr == NULL)
61 | return ERR_PARSING;
62 |
63 | // looks for the opening "
64 | ptr = strchr(ptr, '"');
65 | if(ptr == NULL)
66 | return ERR_PARSING;
67 |
68 | // checks whether the string continues after
69 | ++ptr;
70 | if(*ptr == 0)
71 | return ERR_PARSING;
72 |
73 | // looks for the closing "
74 | end = strchr(ptr, '"');
75 | if(end == NULL)
76 | return ERR_PARSING;
77 |
78 | // copies the option
79 | *end = 0;
80 | int num = atoi(ptr);
81 | *end = '"';
82 |
83 | if((unsigned)num > max)
84 | return ERR_PARSING;
85 |
86 | *dest = num;
87 |
88 | return RET_OK;
89 | }
90 |
91 | // a return code of 0 means that the option was parsed successfully
92 | int parseConfigBool(const char *source, const char *field, bool *dest) {
93 | char *ptr, *end;
94 |
95 | // looks for the keyword
96 | ptr = strstr(source, field);
97 | if(ptr == NULL)
98 | return ERR_PARSING;
99 |
100 | // looks for the opening "
101 | ptr = strchr(ptr, '"');
102 | if(ptr == NULL)
103 | return ERR_PARSING;
104 |
105 | // checks whether the string continues after
106 | ++ptr;
107 | if(*ptr == 0)
108 | return ERR_PARSING;
109 |
110 | // looks for the closing "
111 | end = strchr(ptr, '"');
112 | if(end == NULL)
113 | return ERR_PARSING;
114 |
115 | // copies the option
116 | *end = 0;
117 | *dest = strcmp(ptr, "false");
118 | *end = '"';
119 |
120 | return RET_OK;
121 | }
122 |
123 | // parse the provided config file
124 | void parseConfig(bool error, const char *file, struct SModule *modules, void **ascii_ptr, bool *default_bold, char *default_color, char *default_logo) {
125 | FILE *fp = fopen(file, "r");
126 |
127 | if(fp == NULL) {
128 | if(error)
129 | perror(file);
130 | return;
131 | }
132 |
133 | fseek(fp, 0, SEEK_END);
134 | size_t len = (size_t)ftell(fp);
135 | fseek(fp, 0, SEEK_SET);
136 |
137 | char *conf = malloc(len);
138 | if(conf == NULL) {
139 | perror("malloc");
140 | return;
141 | }
142 | conf[fread(conf, 1, len, fp) - 1] = 0;
143 | fclose(fp);
144 |
145 | // used later
146 | char *ptr, *ptr2;
147 |
148 | // remove comments
149 | uncomment(conf, '#');
150 | uncomment(conf, ';');
151 |
152 | // handle escape sequences
153 | unescape(conf);
154 |
155 | // GENERAL OPTIONS
156 |
157 | // ascii art
158 | char path[96] = "";
159 | parseConfigStr(conf, "ascii_art", path, sizeof(path));
160 | if(path[0])
161 | *ascii_ptr = fileToLogo(path);
162 |
163 | // logo
164 | char logo[32] = "";
165 | parseConfigStr(conf, "logo", logo, sizeof(logo));
166 | if(logo[0]) {
167 | for(size_t i = 0; i < sizeof(logos) / sizeof(logos[0]); ++i)
168 | if(strcmp(logos[i][0], logo) == 0) {
169 | config.logo = logos[i];
170 | strcpy(default_logo, logos[i][0]);
171 | strcpy(config.color, logos[i][1]);
172 | }
173 | }
174 |
175 | // color
176 | char color[16] = "";
177 | parseConfigStr(conf, "default_color", color, sizeof(color));
178 | if(color[0]) {
179 | const char *colors[][2] = {
180 | {"black", "\033[30m"}, {"red", "\033[31m"}, {"green", "\033[32m"}, {"yellow", "\033[33m"}, {"blue", "\033[34m"},
181 | {"purple", "\033[35m"}, {"cyan", "\033[36m"}, {"gray", "\033[90m"}, {"white", "\033[37m"},
182 | };
183 |
184 | for(int i = 0; i < 9; ++i)
185 | if(strcmp(color, *colors[i]) == 0) {
186 | strcpy(config.color, colors[i][1]);
187 | strcpy(default_color, colors[i][1]);
188 | }
189 | }
190 |
191 | // dash
192 | parseConfigStr(conf, "dash", config.dash, sizeof(config.dash));
193 |
194 | // spacing
195 | parseConfigInt(conf, "spacing", &config.spacing, 64);
196 |
197 | // separator
198 | parseConfigStr(conf, "separator_character", config.separator, sizeof(config.separator));
199 |
200 | // BOOLEAN OPTIONS (check utils/utils.h)
201 |
202 | const char *booleanOptions[] = {"align_infos", "bold", "colored_title", "os_arch", "kernel_short", "desktop_type", "shell_path",
203 | "term_ssh", "pkg_mgr", "pkg_pacman", "pkg_dpkg", "pkg_rpm", "pkg_flatpak", "pkg_snap",
204 | "pkg_brew", "pkg_pip", "cpu_brand", "cpu_freq", "cpu_count", "gpu_brand", "mem_perc",
205 | "loc_localhost", "loc_docker", "pwd_path", "kernel_type", "col_background", "bat_status", "swap_perc"};
206 |
207 | bool buffer;
208 | for(size_t i = 0; i < sizeof(booleanOptions) / sizeof(booleanOptions[0]); ++i) {
209 | if(parseConfigBool(conf, booleanOptions[i], &buffer) == 0) {
210 | if(buffer)
211 | config.boolean_options |= ((uint64_t)1 << i);
212 | else
213 | config.boolean_options &= ~((uint64_t)1 << i);
214 | }
215 | }
216 | *default_bold = _bold;
217 |
218 | // OTHER MODULE-RELATED OPTIONS
219 |
220 | parseConfigInt(conf, "gpu_index", &config.gpu_index, 3);
221 |
222 | parseConfigStr(conf, "date_format", config.date_format, sizeof(config.date_format));
223 |
224 | parseConfigStr(conf, "col_block_str", config.col_block_str, sizeof(config.col_block_str));
225 |
226 | // LABELS
227 |
228 | struct SPrefix {
229 | char *option;
230 | const char *config_name;
231 | };
232 |
233 | struct SPrefix prefixes[] = {
234 | // {config.module_prefix, "module_prefix"}
235 | {config.separator_prefix, "separator_prefix"},
236 | {config.spacing_prefix, "spacing_prefix"},
237 | {config.title_prefix, "title_prefix"},
238 | {config.user_prefix, "user_prefix"},
239 | {config.hostname_prefix, "hostname_prefix"},
240 | {config.uptime_prefix, "uptime_prefix"},
241 | {config.os_prefix, "os_prefix"},
242 | {config.kernel_prefix, "kernel_prefix"},
243 | {config.desktop_prefix, "desktop_prefix"},
244 | {config.gtk_theme_prefix, "gtk_theme_prefix"},
245 | {config.icon_theme_prefix, "icon_theme_prefix"},
246 | {config.cursor_theme_prefix, "cursor_theme_prefix"},
247 | {config.shell_prefix, "shell_prefix"},
248 | {config.login_shell_prefix, "login_shell_prefix"},
249 | {config.term_prefix, "term_prefix"},
250 | {config.pkg_prefix, "pkg_prefix"},
251 | {config.host_prefix, "host_prefix"},
252 | {config.bios_prefix, "bios_prefix"},
253 | {config.cpu_prefix, "cpu_prefix"},
254 | {config.gpu_prefix, "gpu_prefix"},
255 | {config.mem_prefix, "mem_prefix"},
256 | {config.swap_prefix, "swap_prefix"},
257 | {config.pub_prefix, "pub_prefix"},
258 | {config.loc_prefix, "loc_prefix"},
259 | {config.pwd_prefix, "pwd_prefix"},
260 | {config.date_prefix, "date_prefix"},
261 | {config.bat_prefix, "bat_prefix"},
262 | {config.colors_prefix, "colors_prefix"},
263 | {config.light_colors_prefix, "colors_light_prefix"},
264 | };
265 |
266 | for(size_t i = 0; i < sizeof(prefixes) / sizeof(prefixes[0]); ++i)
267 | parseConfigStr(conf, prefixes[i].config_name, prefixes[i].option, 64);
268 |
269 | // MODULES
270 |
271 | ptr = strstr(conf, "modules");
272 | if(ptr == NULL) {
273 | free(conf);
274 | return;
275 | }
276 |
277 | ptr2 = strchr(ptr, '{');
278 | if(ptr2 == NULL) {
279 | free(conf);
280 | return;
281 | }
282 |
283 | char *end = strchr(ptr2, '}');
284 | if(end == NULL) {
285 | free(conf);
286 | return;
287 | }
288 | *end = 0;
289 |
290 | while((ptr = strchr(ptr2, '"'))) {
291 | ++ptr;
292 |
293 | ptr2 = strchr(ptr, '"');
294 | if(ptr2 == NULL) {
295 | free(conf);
296 | return;
297 | }
298 | *ptr2 = 0;
299 |
300 | addModule(modules, ptr);
301 |
302 | // *ptr2 = '"';
303 | ++ptr2;
304 | }
305 |
306 | // *end = '}';
307 |
308 | free(conf);
309 | }
310 |
--------------------------------------------------------------------------------
/src/config/config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../utils/utils.h"
4 |
5 | #include
6 | #include
7 |
8 | struct SConfig {
9 | /* Starting from the least significant byte, see the #define statements later
10 | * 0. _align
11 | * 1. _bold
12 | * 2. _title_color
13 | * 3. _os_arch
14 | * 4. _kernel_short
15 | * 5. _de_type
16 | * 6. _shell_path
17 | * 7. _term_ssh
18 | * 8. _pkg_mgr
19 | * 9. _pkg_pacman
20 | * 10. _pkg_dpkg
21 | * 11. _pkg_rpm
22 | * 12. _pkg_flatpak
23 | * 13. _pkg_snap
24 | * 14. _pkg_brew
25 | * 15. _pkg_pip
26 | * 16. _cpu_brand
27 | * 17. _cpu_freq
28 | * 18. _cpu_count
29 | * 19. _gpu_brand
30 | * 20. _mem_perc
31 | * 21. _loc_localhost
32 | * 22. _loc_docker
33 | * 23. _pwd_path
34 | * 24. _col_background
35 | * 25. _bat_status
36 | * 26. _swap_perc
37 | * [...]
38 | */
39 | uint64_t boolean_options;
40 |
41 | char **logo;
42 | char color[8];
43 | char dash[16];
44 | char separator[8];
45 | int spacing;
46 |
47 | int gpu_index;
48 | char date_format[32];
49 | char col_block_str[24];
50 |
51 | char separator_prefix[64];
52 | char spacing_prefix[64];
53 | char title_prefix[64];
54 | char user_prefix[64];
55 | char hostname_prefix[64];
56 | char uptime_prefix[64];
57 | char os_prefix[64];
58 | char kernel_prefix[64];
59 | char desktop_prefix[64];
60 | char gtk_theme_prefix[64];
61 | char icon_theme_prefix[64];
62 | char cursor_theme_prefix[64];
63 | char shell_prefix[64];
64 | char login_shell_prefix[64];
65 | char term_prefix[64];
66 | char pkg_prefix[64];
67 | char host_prefix[64];
68 | char bios_prefix[64];
69 | char cpu_prefix[64];
70 | char gpu_prefix[64];
71 | char mem_prefix[64];
72 | char swap_prefix[64];
73 | char pub_prefix[64];
74 | char loc_prefix[64];
75 | char pwd_prefix[64];
76 | char date_prefix[64];
77 | char bat_prefix[64];
78 | char colors_prefix[64];
79 | char light_colors_prefix[64];
80 | };
81 | extern struct SConfig config;
82 |
83 | #define _align config.boolean_options & 0x1
84 | #define _bold config.boolean_options & 0x2
85 | #define _title_color config.boolean_options & 0x4
86 | #define _os_arch config.boolean_options & 0x8
87 | #define _kernel_short config.boolean_options & 0x10
88 | #define _de_type config.boolean_options & 0x20
89 | #define _shell_path config.boolean_options & 0x40
90 | #define _term_ssh config.boolean_options & 0x80
91 | #define _pkg_mgr config.boolean_options & 0x100
92 | #define _pkg_pacman config.boolean_options & 0x200
93 | #define _pkg_dpkg config.boolean_options & 0x400
94 | #define _pkg_rpm config.boolean_options & 0x800
95 | #define _pkg_flatpak config.boolean_options & 0x1000
96 | #define _pkg_snap config.boolean_options & 0x2000
97 | #define _pkg_brew config.boolean_options & 0x4000
98 | #define _pkg_pip config.boolean_options & 0x8000
99 | #define _cpu_brand config.boolean_options & 0x10000
100 | #define _cpu_freq config.boolean_options & 0x20000
101 | #define _cpu_count config.boolean_options & 0x40000
102 | #define _gpu_brand config.boolean_options & 0x80000
103 | #define _mem_perc config.boolean_options & 0x100000
104 | #define _loc_localhost config.boolean_options & 0x200000
105 | #define _loc_docker config.boolean_options & 0x400000
106 | #define _pwd_path config.boolean_options & 0x800000
107 | #define _kernel_type config.boolean_options & 0x1000000
108 | #define _col_background config.boolean_options & 0x2000000
109 | #define _bat_status config.boolean_options & 0x4000000
110 | #define _swap_perc config.boolean_options & 0x8000000
111 |
112 | void parseConfig(bool error, const char *file, struct SModule *modules, void **ascii_ptr, bool *default_bold, char *default_color, char *default_logo);
113 |
--------------------------------------------------------------------------------
/src/config/parsing.c:
--------------------------------------------------------------------------------
1 | #include "config.h"
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #include "../utils/return.h"
8 |
9 | // TODO: rewrite config parsing from scratch
10 |
11 | /*
12 |
13 | // checks if the given character is between two " "
14 | bool is_in_string(const char *str, const char *place) {
15 | int count = 0;
16 |
17 | char *ptr = (char*)str;
18 | while((ptr = strchr(ptr, '"')) && ptr < (char*)place) {
19 | ++count;
20 | ptr += 1;
21 | }
22 |
23 | if(count % 2 == 1)
24 | return true;
25 |
26 | return false;
27 | }
28 |
29 | // skip every whitespace, return the first full character
30 | char *skip_whites(char *ptr) {
31 | if(ptr == NULL)
32 | return NULL;
33 | if(ptr[0] == 0)
34 | return NULL;
35 |
36 | while(*ptr) {
37 | if(*ptr != ' ' && *ptr != '\n' && *ptr != '\t')
38 | return ptr;
39 | ++ptr;
40 | }
41 |
42 | return NULL;
43 | }
44 |
45 | // skip every full character, return the first whitespace
46 | char *skip_full(char *ptr) {
47 | if(ptr == NULL)
48 | return NULL;
49 |
50 | while(*ptr) {
51 | if(*ptr == ' ' || *ptr == '\n' || *ptr == '\t')
52 | return ptr;
53 | ++ptr;
54 | }
55 |
56 | return NULL;
57 | }
58 |
59 | */
60 |
61 | // remove comments, aka from start to the end of the line
62 | void uncomment(char *str, const char start) {
63 | char *ptr = str, *ptr2;
64 | while((ptr = strchr(ptr, start))) {
65 | // when it is between two " (aka the number of " before it is odd)
66 | int counter = 0;
67 | ptr2 = str;
68 | while((ptr2 = strchr(ptr2, '"')) && ptr2 < ptr) {
69 | ++ptr2;
70 | ++counter;
71 | }
72 | if(counter & 1) {
73 | ++ptr;
74 | continue;
75 | }
76 |
77 | ptr2 = strchr(ptr, '\n');
78 |
79 | if(ptr2 == NULL) {
80 | *ptr = 0;
81 | break;
82 | }
83 |
84 | memmove(ptr, ptr2 + 1, strlen(ptr2));
85 | }
86 | }
87 |
88 | // check every '\' in str and unescape "\\" "\n" "\e" "\033"
89 | void unescape(char *str) {
90 | while((str = strchr(str, '\\'))) {
91 | switch(str[1]) {
92 | case 'e':
93 | memmove(str, str + 1, strlen(str));
94 | *str = '\033';
95 | break;
96 | case '0':
97 | if(str[2] == '3' && str[3] == '3') {
98 | memmove(str, str + 3, strlen(str + 2));
99 | *str = '\033';
100 | }
101 | break;
102 | case 'n':
103 | memmove(str, str + 1, strlen(str));
104 | *str = '\n';
105 | break;
106 | default: // takes care of "\\" and any other sort of "\X"
107 | memmove(str, str + 1, strlen(str));
108 | ++str;
109 | break;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/config/parsing.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | // bool is_in_string(const char *str, const char *place);
6 |
7 | // char *skip_whites(char *ptr);
8 |
9 | // char *skip_full(char *ptr);
10 |
11 | void uncomment(char *str, const char start);
12 |
13 | void unescape(char *str);
14 |
--------------------------------------------------------------------------------
/src/debug.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is not part of albafetch.
3 | * All it does is check whether every single module is working, and what might not be working.
4 | * Useful for checking what info I'm able to get on multiple systems.
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 |
11 | #include "config/config.h"
12 | #include "info/info.h"
13 | #include "utils/return.h"
14 | #include "utils/utils.h"
15 | #ifdef HAVE_VERSION_H
16 | #include "version.h" // generated by meson - defines COMMIT and VERSION
17 | #else
18 | #define VERSION "[UNKNOWN]"
19 | #define COMMIT "[UNKNOWN]"
20 | #endif // HAVE_VERSION_H
21 |
22 | // Most of those aren't even needed
23 | struct SConfig config;
24 |
25 | int main(int argc, char **argv) {
26 | puts("version: \033[1m\033[34m" VERSION "\033[0m, commit: \033[1m\033[34m" COMMIT "\033[0m\n");
27 |
28 | struct SModule {
29 | int (*func)(char *);
30 | char *name;
31 | };
32 | struct SModule arr[] = {{user, "user"},
33 | {hostname, "hostname"},
34 | {uptime, "uptime"},
35 | {os, "os"},
36 | {kernel, "kernel"},
37 | {desktop, "desktop"},
38 | {gtkTheme, "gtk_theme"},
39 | {iconTheme, "icon_theme"},
40 | {cursorTheme, "cursor_theme"},
41 | {shell, "shell"},
42 | {loginShell, "login_shell"},
43 | {term, "term"},
44 | {packages, "packages"},
45 | {host, "host"},
46 | {bios, "bios"},
47 | {cpu, "cpu"},
48 | {gpu, "gpu"},
49 | {memory, "memory"},
50 | {swap, "swap"},
51 | {publicIp, "public_ip"},
52 | {localIp, "local_ip"},
53 | {pwd, "pwd"},
54 | {date, "date"},
55 | {battery, "battery"},
56 | {colors, "colors"},
57 | {lightColors, "light_colors"}};
58 |
59 | unsigned errors = 0;
60 | int return_value;
61 | char mem[DEST_SIZE];
62 |
63 | struct timeval start, end, start_all;
64 | double time;
65 |
66 | // just setting every option to 1 (except maybe _pkg_pip cause pip is slow af)
67 | if(argc > 1)
68 | config.boolean_options = strcmp(argv[1], "--no-pip") ? 0xffffffffffffffff : 0xffffffffffff7fff;
69 | else
70 | config.boolean_options = 0xffffffffffffffff;
71 | // these are just defaults
72 | strcpy(config.col_block_str, " ");
73 | strcpy(config.date_format, "%02d/%02d/%d %02d:%02d:%02d");
74 |
75 | gettimeofday(&start_all, NULL);
76 |
77 | for(unsigned long i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i) {
78 | gettimeofday(&start, NULL);
79 |
80 | return_value = arr[i].func(mem);
81 |
82 | gettimeofday(&end, NULL);
83 |
84 | time = ((end.tv_sec - start.tv_sec) * 1e6 + end.tv_usec - start.tv_usec) / 1e3;
85 |
86 | if(return_value == 0) {
87 | printf("\033[1m\033[32m%-12s\033[0m %-40s [\033[1m\033[36m\033[1m%.3f ms\033[0m]\n", arr[i].name, mem, time);
88 | } else {
89 | printf("\033[1m\033[31m%-13s\033[0m 0x%-38x"
90 | "[\033[1m\033[36m\033[1m%.3f ms\033[0m]\n",
91 | arr[i].name, return_value, time);
92 | ++errors;
93 | }
94 | }
95 |
96 | gettimeofday(&end, NULL);
97 | time = ((end.tv_sec - start_all.tv_sec) * 1e6 + end.tv_usec - start_all.tv_usec) / 1e3;
98 |
99 | printf("\n\033[1mDebug run finished with a total of %u errors.\033[0m [\033[1m\033[36m\033[1m%.3f ms\033[0m]\n", errors, time);
100 |
101 | return RET_OK;
102 | }
103 |
--------------------------------------------------------------------------------
/src/info/battery.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #ifdef __ANDROID__
6 | #include
7 | #endif // __ANDROID__
8 |
9 | #include "info.h"
10 | #include "../config/config.h"
11 | #include "../utils/wrappers.h"
12 |
13 | // get the battery percentage and status (Linux only!)
14 | int battery(char *dest) {
15 | char capacity[5] = "";
16 | char status[20] = "";
17 |
18 | #ifdef __ANDROID__ // relies on termux api
19 | char buf[DEST_SIZE];
20 | char *args[] = {"termux-battery-status", NULL};
21 | execCmd(buf, DEST_SIZE, args);
22 |
23 | char *ptr = strstr(buf, "percentage");
24 | char *ptr2 = strstr(buf, "status");
25 | char *end;
26 |
27 | if(ptr != NULL) {
28 | ptr += 13;
29 | end = strchr(ptr, ',');
30 | if(end != NULL) {
31 | *end = 0;
32 | safeStrncpy(capacity, ptr, 5);
33 | }
34 | }
35 |
36 | if(ptr2 != NULL) {
37 | ptr2 += 10;
38 | end = strstr(ptr2, "\",");
39 | ptr = ptr2 + 1;
40 | while(*ptr) {
41 | *ptr = tolower(*ptr);
42 |
43 | ++ptr;
44 | }
45 |
46 | if(end != NULL) {
47 | *end = 0;
48 | safeStrncpy(status, ptr2, 20);
49 | }
50 | }
51 | #else
52 | FILE *fp = NULL;
53 |
54 | if((fp = fopen("/sys/class/power_supply/BAT0/capacity", "r"))) {
55 | capacity[fread(capacity, 1, 5, fp) - 1] = 0;
56 |
57 | fclose(fp);
58 | }
59 | if((fp = fopen("/sys/class/power_supply/BAT0/status", "r"))) {
60 | status[fread(status, 1, 20, fp) - 1] = 0;
61 |
62 | fclose(fp);
63 | }
64 | #endif // __ANDROID__
65 |
66 | if(capacity[0] != 0 && status[0] != 0) {
67 | if((_bat_status))
68 | snprintf(dest, DEST_SIZE, "%s%% (%s)", capacity, status);
69 | else
70 | snprintf(dest, DEST_SIZE, "%s%%", capacity);
71 | } else if(capacity[0] != 0)
72 | snprintf(dest, DEST_SIZE, "%s%%", capacity);
73 | else if(status[0] != 0 && (_bat_status))
74 | safeStrncpy(dest, status, DEST_SIZE);
75 | else
76 | return ERR_NO_INFO;
77 |
78 | return RET_OK;
79 | }
80 |
--------------------------------------------------------------------------------
/src/info/bios.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 |
6 | #include "info.h"
7 | #include "../utils/wrappers.h"
8 |
9 | // get the current BIOS vendor and version (Linux only!)
10 | int bios(char *dest) {
11 | char *vendor = NULL, *version = NULL;
12 | FILE *fp = NULL;
13 | size_t len;
14 |
15 | if((fp = fopen("/sys/devices/virtual/dmi/id/bios_vendor", "r"))) {
16 | fseek(fp, 0, SEEK_END);
17 | len = ftell(fp);
18 | fseek(fp, 0, SEEK_SET);
19 |
20 | vendor = malloc(len);
21 | if(vendor == NULL)
22 | return ERR_OOM;
23 | vendor[fread(vendor, 1, len, fp) - 1] = 0;
24 |
25 | fclose(fp);
26 | }
27 |
28 | if((fp = fopen("/sys/devices/virtual/dmi/id/bios_version", "r"))) {
29 | fseek(fp, 0, SEEK_END);
30 | len = ftell(fp);
31 | fseek(fp, 0, SEEK_SET);
32 |
33 | version = malloc(len);
34 | if(version == NULL) {
35 | free(vendor);
36 | return ERR_OOM;
37 | }
38 | version[fread(version, 1, len, fp) - 1] = 0;
39 |
40 | fclose(fp);
41 | }
42 |
43 | if(vendor != NULL && version != NULL)
44 | snprintf(dest, DEST_SIZE, "%s %s", vendor, version);
45 | else if(vendor != NULL)
46 | safeStrncpy(dest, vendor, DEST_SIZE);
47 | else if(version != NULL)
48 | safeStrncpy(dest, version, DEST_SIZE);
49 | else
50 | return ERR_NO_INFO;
51 |
52 | free(vendor);
53 | free(version);
54 |
55 | return RET_OK;
56 | }
57 |
--------------------------------------------------------------------------------
/src/info/colors.c:
--------------------------------------------------------------------------------
1 | #include "info.h"
2 | #include "../config/config.h"
3 |
4 | #include
5 |
6 | #include
7 |
8 | // show the terminal color configuration
9 | int colors(char *dest) {
10 | memset(dest, 0, DEST_SIZE);
11 |
12 | for(int i = 0; i < 8; ++i)
13 | sprintf(dest + strlen(dest), "\033[%s%dm%s", _col_background ? "4" : "3", i, config.col_block_str);
14 |
15 | strcat(dest, "\033[0m");
16 |
17 | return RET_OK;
18 | }
19 |
--------------------------------------------------------------------------------
/src/info/cpu.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #ifdef __APPLE__
6 | #include
7 | #endif // __APPLE__
8 |
9 | #include "info.h"
10 | #include "../config/config.h"
11 | #include "../utils/wrappers.h"
12 |
13 | // get the cpu name and frequency
14 | int cpu(char *dest) {
15 | char *cpu_info;
16 | char *end;
17 | int count = 0;
18 | char freq[24] = "";
19 |
20 | #ifdef __APPLE__
21 | size_t BUF_SIZE = DEST_SIZE;
22 | char buf[BUF_SIZE];
23 | buf[0] = 0;
24 | sysctlbyname("machdep.cpu.brand_string", buf, &BUF_SIZE, NULL, 0);
25 |
26 | if(buf[0] == 0)
27 | return ERR_NO_INFO;
28 |
29 | if((_cpu_freq) == 0) {
30 | if((end = strstr(buf, " @")))
31 | *end = 0;
32 | else if((end = strchr(buf, '@')))
33 | *end = 0;
34 | }
35 |
36 | cpu_info = buf;
37 | #else
38 | FILE *fp = fopen("/proc/cpuinfo", "r");
39 | if(fp == NULL)
40 | return ERR_NO_FILE;
41 |
42 | char *buf = malloc(0x10000);
43 | if(buf == NULL)
44 | return ERR_OOM;
45 | buf[fread(buf, 1, 0x10000, fp)] = 0;
46 | fclose(fp);
47 |
48 | cpu_info = buf;
49 | if(_cpu_count) {
50 | end = cpu_info;
51 | while((end = strstr(end, "processor"))) {
52 | ++count;
53 | ++end;
54 | }
55 | }
56 |
57 | cpu_info = strstr(cpu_info, "model name");
58 | if(cpu_info == NULL) {
59 | free(buf);
60 | return ERR_PARSING;
61 | }
62 |
63 | cpu_info += 13;
64 |
65 | end = strstr(cpu_info, " @");
66 | if(end)
67 | *end = 0;
68 | else {
69 | end = strchr(cpu_info, '\n');
70 | if(end == NULL) {
71 | free(buf);
72 | return ERR_PARSING + 0x10;
73 | }
74 |
75 | *end = 0;
76 | }
77 |
78 | /* I might eventually add an option to get the "default" clock speed
79 | * by parsing one or more of the following files:
80 | * - /sys/devices/system/cpu/cpu0/cpufreq/cpupower_max_freq
81 | * - /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
82 | * - /sys/devices/system/cpu/cpu0/cpufreq/bios_limit
83 | * - /sys/devices/system/cpu/cpu0/cpufreq/base_frequency
84 | */
85 | // Printing the clock frequency the first thread is currently running at
86 | ++end;
87 | char *frequency = strstr(end, "cpu MHz");
88 | if(frequency && _cpu_freq) {
89 | frequency = strchr(frequency, ':');
90 | if(frequency) {
91 | frequency += 2;
92 |
93 | end = strchr(frequency, '\n');
94 | if(end) {
95 | *end = 0;
96 |
97 | snprintf(freq, 24, " @ %.2g GHz", atof(frequency) / 1e3);
98 | }
99 | }
100 | }
101 | #endif
102 |
103 | // cleaning the string from various garbage
104 | if((end = strstr(cpu_info, "(R)")))
105 | memmove(end, end + 3, strlen(end + 3) + 1);
106 | if((end = strstr(cpu_info, "(TM)")))
107 | memmove(end, end + 4, strlen(end + 4) + 1);
108 | if((end = strstr(cpu_info, " CPU")))
109 | memmove(end, end + 4, strlen(end + 4) + 1);
110 | if((end = strstr(cpu_info, "th Gen ")))
111 | memmove(end - 2, end + 7, strlen(end + 7) + 1);
112 | if((end = strstr(cpu_info, " with Radeon Graphics")))
113 | *end = 0;
114 | if((end = strstr(cpu_info, "-Core Processor"))) {
115 | if(end >= cpu_info + 5) {
116 | end -= 5;
117 | end = strchr(end, ' ');
118 | if(end != NULL)
119 | *end = 0;
120 | }
121 | }
122 |
123 | if((_cpu_brand) == 0) {
124 | if((end = strstr(cpu_info, "Intel Core ")))
125 | memmove(end, end + 11, strlen(end + 1));
126 | else if((end = strstr(cpu_info, "Apple ")))
127 | memmove(end, end + 6, strlen(end + 6) + 1);
128 | else if((end = strstr(cpu_info, "AMD ")))
129 | memmove(end, end + 4, strlen(end + 1));
130 | }
131 |
132 | safeStrncpy(dest, cpu_info, DEST_SIZE);
133 | #ifdef __linux__
134 | free(buf);
135 | #endif
136 |
137 | if(freq[0])
138 | strncat(dest, freq, DEST_SIZE - 1 - strlen(dest));
139 |
140 | if(count && _cpu_count) {
141 | char core_count[16];
142 | snprintf(core_count, 16, " (%d) ", count);
143 | strncat(dest, core_count, DEST_SIZE - 1 - strlen(dest));
144 | }
145 | // final cleanup ("Intel Core i5 650" lol)
146 | while((end = strstr(dest, " ")))
147 | memmove(end, end + 1, strlen(end));
148 |
149 | return RET_OK;
150 | }
151 |
--------------------------------------------------------------------------------
/src/info/cursor_theme.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "info.h"
7 | #include "../optdeps/optdeps.h"
8 | #include "../utils/wrappers.h"
9 |
10 | // get the current Cursor Theme
11 | int cursorTheme(char *dest) {
12 | // try using gsettings
13 | // reading ~/.config/gtk-3.0/settings.ini could also be an option
14 | if(binaryInPath("gsettings")) {
15 | char buf[DEST_SIZE] = "";
16 | char *args[] = {"gsettings", "get", "org.gnome.desktop.interface", "cursor-theme", NULL};
17 | execCmd(buf, DEST_SIZE, args);
18 |
19 | // cleanup
20 | if(buf[0] != 0) {
21 | if(buf[0] == '\'') {
22 | memmove(buf, buf + 1, strlen(buf));
23 |
24 | char *ptr = strchr(buf, '\'');
25 | if(ptr)
26 | *ptr = 0;
27 | }
28 |
29 | safeStrncpy(dest, buf, DEST_SIZE);
30 | return RET_OK;
31 | }
32 | }
33 |
34 | return ERR_UNSUPPORTED;
35 | }
36 |
--------------------------------------------------------------------------------
/src/info/date.c:
--------------------------------------------------------------------------------
1 | #include "info.h"
2 | #include "../config/config.h"
3 |
4 | #include
5 |
6 | #include
7 | #include
8 |
9 | // get the current date and time
10 | int date(char *dest) {
11 | time_t t = time(NULL);
12 | struct tm tm = *localtime(&t);
13 | snprintf(dest, DEST_SIZE, config.date_format, tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec);
14 | return RET_OK;
15 | }
16 |
--------------------------------------------------------------------------------
/src/info/desktop.c:
--------------------------------------------------------------------------------
1 | #include "info.h"
2 | #include "../config/config.h"
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | // get the current desktop environment
11 | int desktop(char *dest) {
12 | #ifdef __APPLE__
13 | strcpy(dest, "Aqua");
14 | #else
15 | char *desktop = getenv("SWAYSOCK") ? "Sway" :
16 | (desktop = getenv("XDG_CURRENT_DESKTOP")) ? desktop :
17 | (desktop = getenv("DESKTOP_SESSION")) ? desktop :
18 | getenv("KDE_SESSION_VERSION") ? "KDE" :
19 | getenv("GNOME_DESKTOP_SESSION_ID") ? "GNOME" :
20 | getenv("MATE_DESKTOP_SESSION_ID") ? "MATE" :
21 | getenv("TDE_FULL_SESSION") ? "Trinity" :
22 | // strcmp("linux", getenv("TERM") == 0 ? "none" : // running in tty
23 | NULL;
24 | if(desktop == NULL)
25 | return ERR_NO_INFO;
26 |
27 | strcpy(dest, desktop);
28 |
29 | if(_de_type) {
30 | if(getenv("WAYLAND_DISPLAY"))
31 | strncat(dest, " (Wayland)", DEST_SIZE - strlen(dest));
32 | else if((desktop = getenv("XDG_SESSION_TYPE"))) {
33 | if(desktop[0] == 0)
34 | return RET_OK;
35 | desktop[0] = toupper(desktop[0]);
36 |
37 | char buf[32];
38 | snprintf(buf, 32, " (%s) ", desktop);
39 | strncat(dest, buf, DEST_SIZE - 1 - strlen(dest));
40 | }
41 | }
42 | #endif
43 |
44 | return RET_OK;
45 | }
46 |
--------------------------------------------------------------------------------
/src/info/gpu.c:
--------------------------------------------------------------------------------
1 | #include "info.h"
2 | #include "../config/config.h"
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | #ifdef __APPLE__
11 | #include
12 | #include "../macos/macos_infos.h"
13 | #include "../utils/wrappers.h"
14 | #else
15 | #ifndef __ANDROID__
16 | #include "../optdeps/optdeps.h"
17 | #endif // __ANDROID__
18 | #endif // __APPLE__
19 |
20 | // get the gpu name(s)
21 | int gpu(char *dest) {
22 | char *gpus[] = {NULL, NULL, NULL};
23 |
24 | #ifdef __APPLE__
25 | struct utsname name;
26 | uname(&name);
27 |
28 | if(strcmp(name.machine, "x86_64") == 0)
29 | gpus[0] = getGpuString(); // only works on x64
30 | if(gpus[0] == 0 || strcmp(name.machine, "x86_64")) { // fallback
31 | char buf[1024];
32 | char *args[] = {"/usr/sbin/system_profiler", "SPDisplaysDataType", NULL};
33 | execCmd(buf, 1024, args);
34 |
35 | gpus[0] = strstr(buf, "Chipset Model: ");
36 | if(gpus[0] == 0)
37 | return ERR_NO_INFO;
38 | gpus[0] += 15;
39 | char *end = strchr(gpus[0], '\n');
40 | if(end == NULL)
41 | return ERR_PARSING;
42 | *end = 0;
43 | }
44 | #else
45 | #ifdef __ANDROID__
46 | return ERR_UNSUPPORTED;
47 | #else
48 | getGpus(gpus);
49 | #endif // __ANDROID__
50 | #endif // __APPLE__
51 |
52 | if(gpus[0] == NULL)
53 | return ERR_NO_INFO;
54 |
55 | // this next part is just random cleanup
56 | // also, I'm using end as a random char* - BaD pRaCtIcE aNd CoNfUsInG - lol stfu
57 | // yk it's decent and it works
58 | dest[0] = 0;
59 | for(unsigned i = 0; i < sizeof(gpus) / sizeof(gpus[0]) && gpus[i] != NULL; ++i) {
60 | if((_gpu_brand) == 0) {
61 | if(strstr(gpus[i], "Intel ") || strstr(gpus[i], "Apple "))
62 | gpus[i] += 6;
63 | else if(strstr(gpus[i], "AMD "))
64 | gpus[i] += 4;
65 | }
66 |
67 | char *end = strchr(gpus[i], '[');
68 | if(end) { // sometimes the gpu is "Architecture [GPU Name]"
69 | char *ptr = strchr(end, ']');
70 | if(ptr) {
71 | gpus[i] = end + 1;
72 | *ptr = 0;
73 | }
74 | }
75 |
76 | if((end = strstr(gpus[i], " Integrated Graphics Controller")))
77 | *end = 0;
78 | if((end = strstr(gpus[i], " Rev. ")))
79 | *end = 0;
80 |
81 | // (finally) writing the GPU(s) into dest
82 | if(i > 0)
83 | strncat(dest, ", ", DEST_SIZE - strlen(dest));
84 | strncat(dest, gpus[i], DEST_SIZE - 1 - strlen(dest));
85 | }
86 |
87 | return RET_OK;
88 | }
89 |
--------------------------------------------------------------------------------
/src/info/gtk_theme.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "info.h"
7 | #include "../optdeps/optdeps.h"
8 | #include "../utils/wrappers.h"
9 |
10 | // get the current GTK Theme
11 | int gtkTheme(char *dest) {
12 | char *theme = getenv("GTK_THEME");
13 |
14 | // try using GTK_THEME (faster)
15 | if(theme) {
16 | safeStrncpy(dest, theme, DEST_SIZE);
17 |
18 | return RET_OK;
19 | }
20 |
21 | // try using gsettings (fallback)
22 | // reading ~/.config/gtk-3.0/settings.ini could also be an option
23 | if(binaryInPath("gsettings")) {
24 | char buf[DEST_SIZE] = "";
25 | char *args[] = {"gsettings", "get", "org.gnome.desktop.interface", "gtk-theme", NULL};
26 | execCmd(buf, DEST_SIZE, args);
27 |
28 | // cleanup
29 | if(buf[0] != 0) {
30 | if(buf[0] == '\'') {
31 | memmove(buf, buf + 1, strlen(buf));
32 |
33 | char *ptr = strchr(buf, '\'');
34 | if(ptr)
35 | *ptr = 0;
36 | }
37 |
38 | safeStrncpy(dest, buf, DEST_SIZE);
39 | return RET_OK;
40 | }
41 | }
42 |
43 | return ERR_UNSUPPORTED;
44 | }
45 |
--------------------------------------------------------------------------------
/src/info/host.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #ifdef __APPLE__
8 | #include
9 | #else
10 | #ifdef __ANDROID__
11 | #include
12 | #include
13 |
14 | #include "../utils/wrappers.h"
15 | #else
16 | #include "../utils/wrappers.h"
17 | #endif // __ANDROID__
18 | #endif // __APPLE__
19 |
20 | #include "info.h"
21 |
22 | // get the machine name and eventually model version
23 | int host(char *dest) {
24 | #ifdef __APPLE__
25 | size_t BUF_SIZE = DEST_SIZE;
26 | sysctlbyname("hw.model", dest, &BUF_SIZE, NULL, 0);
27 | #else
28 | #ifdef __ANDROID__
29 | char brand[64], model[64];
30 | char *brand_args[] = {"getprop", "ro.product.brand", NULL};
31 | char *model_args[] = {"getprop", "ro.product.model", NULL};
32 |
33 | execCmd(brand, 64, brand_args);
34 | execCmd(model, 64, model_args);
35 |
36 | if((brand[0] || model[0]) == 0)
37 | return ERR_NO_INFO;
38 |
39 | snprintf(dest, DEST_SIZE, "%s%s%s", brand, brand[0] ? " " : "", model);
40 | #else
41 | char *name = NULL, *version = NULL;
42 | FILE *fp = NULL;
43 | size_t len;
44 |
45 | if((fp = fopen("/sys/devices/virtual/dmi/id/product_name", "r"))) {
46 | fseek(fp, 0, SEEK_END);
47 | len = ftell(fp);
48 | fseek(fp, 0, SEEK_SET);
49 |
50 | name = malloc(len);
51 | if(name == NULL)
52 | return ERR_OOM;
53 | name[fread(name, 1, len, fp) - 1] = 0;
54 |
55 | fclose(fp);
56 | }
57 |
58 | if((fp = fopen("/sys/devices/virtual/dmi/id/product_version", "r"))) {
59 | fseek(fp, 0, SEEK_END);
60 | len = ftell(fp);
61 | fseek(fp, 0, SEEK_SET);
62 |
63 | version = malloc(len);
64 | if(version == NULL)
65 | return ERR_OOM;
66 | version[fread(version, 1, len, fp) - 1] = 0;
67 |
68 | fclose(fp);
69 | }
70 |
71 | // filtering out some shitty defaults because the file can't just be empty"
72 | const char *errors[] = {"System Product Name", "System Version", "To Be Filled By O.E.M.", "None", ""};
73 | bool name_defined = true;
74 | bool version_defined = true;
75 |
76 | for(unsigned long i = 0; i < sizeof(errors) / sizeof(errors[0]); ++i) {
77 | if(name)
78 | if(strcmp(name, errors[i]) == 0)
79 | name_defined = false;
80 | if(version)
81 | if(strcmp(version, errors[i]) == 0)
82 | version_defined = false;
83 | }
84 |
85 | if(name && version && name_defined && version_defined)
86 | snprintf(dest, DEST_SIZE, "%s %s", name, version);
87 | else if(name && name_defined)
88 | safeStrncpy(dest, name, DEST_SIZE);
89 | else if(version && version_defined)
90 | safeStrncpy(dest, version, DEST_SIZE);
91 | else {
92 | free(name);
93 | free(version);
94 |
95 | return ERR_NO_INFO;
96 | }
97 |
98 | free(name);
99 | free(version);
100 | #endif // __ANDROID__
101 | #endif // __APPLE__
102 |
103 | return RET_OK;
104 | }
105 |
--------------------------------------------------------------------------------
/src/info/hostname.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "info.h"
6 | #include "../utils/wrappers.h"
7 |
8 | // idk why but this is sometimes not defined
9 | #ifndef HOST_NAME_MAX
10 | #ifdef _POSIX_HOST_NAME_MAX
11 | #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
12 | #else
13 | #define HOST_NAME_MAX 255
14 | #endif
15 | #endif
16 |
17 | // print the machine hostname
18 | int hostname(char *dest) {
19 | char hostname[HOST_NAME_MAX + 1];
20 | gethostname(hostname, HOST_NAME_MAX + 1);
21 |
22 | char *ptr = strstr(hostname, ".local");
23 | if(ptr)
24 | *ptr = 0;
25 |
26 | safeStrncpy(dest, hostname, DEST_SIZE);
27 |
28 | return RET_OK;
29 | }
30 |
--------------------------------------------------------------------------------
/src/info/icon_theme.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "info.h"
7 | #include "../optdeps/optdeps.h"
8 | #include "../utils/wrappers.h"
9 |
10 | // get the current Icon Theme
11 | int iconTheme(char *dest) {
12 | // try using gsettings
13 | // reading ~/.config/gtk-3.0/settings.ini could also be an option
14 | if(binaryInPath("gsettings")) {
15 | char buf[DEST_SIZE] = "";
16 | char *args[] = {"gsettings", "get", "org.gnome.desktop.interface", "icon-theme", NULL};
17 | execCmd(buf, DEST_SIZE, args);
18 |
19 | // cleanup
20 | if(buf[0] != 0) {
21 | if(buf[0] == '\'') {
22 | memmove(buf, buf + 1, strlen(buf));
23 |
24 | char *ptr = strchr(buf, '\'');
25 | if(ptr)
26 | *ptr = 0;
27 | }
28 |
29 | safeStrncpy(dest, buf, DEST_SIZE);
30 | return RET_OK;
31 | }
32 | }
33 |
34 | return ERR_UNSUPPORTED;
35 | }
36 |
--------------------------------------------------------------------------------
/src/info/info.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../utils/return.h"
4 |
5 | #define DEST_SIZE 256
6 |
7 | int user(char *dest);
8 |
9 | int hostname(char *dest);
10 |
11 | int uptime(char *dest);
12 |
13 | int os(char *dest);
14 |
15 | int kernel(char *dest);
16 |
17 | int desktop(char *dest);
18 |
19 | int gtkTheme(char *dest);
20 |
21 | int iconTheme(char *dest);
22 |
23 | int cursorTheme(char *dest);
24 |
25 | int shell(char *dest);
26 |
27 | int loginShell(char *dest);
28 |
29 | int term(char *dest);
30 |
31 | int packages(char *dest);
32 |
33 | int host(char *dest);
34 |
35 | int bios(char *dest);
36 |
37 | int cpu(char *dest);
38 |
39 | int gpu(char *dest);
40 |
41 | int memory(char *dest);
42 |
43 | int swap(char *dest);
44 |
45 | int publicIp(char *dest);
46 |
47 | int localIp(char *dest);
48 |
49 | int pwd(char *dest);
50 |
51 | int date(char *dest);
52 |
53 | int battery(char *dest);
54 |
55 | int colors(char *dest);
56 |
57 | int lightColors(char *dest);
58 |
--------------------------------------------------------------------------------
/src/info/kernel.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "info.h"
6 | #include "../config/config.h"
7 | #include "../utils/wrappers.h"
8 |
9 | // print the running kernel version (uname -r)
10 | int kernel(char *dest) {
11 | struct utsname name;
12 | uname(&name);
13 | char *ptr = name.release, *type = NULL;
14 |
15 | if(_kernel_type) {
16 | while((ptr = strchr(ptr, '-')))
17 | type = ++ptr;
18 | }
19 |
20 | if(_kernel_short) {
21 | if((ptr = strchr(name.release, '-')))
22 | *ptr = 0;
23 | }
24 |
25 | if(_kernel_type && type)
26 | snprintf(dest, DEST_SIZE, "%s (%s)", name.release, type);
27 | else
28 | safeStrncpy(dest, name.release, DEST_SIZE);
29 |
30 | return RET_OK;
31 | }
32 |
--------------------------------------------------------------------------------
/src/info/light_colors.c:
--------------------------------------------------------------------------------
1 | #include "info.h"
2 | #include "../config/config.h"
3 |
4 | #include
5 |
6 | #include
7 |
8 | // show the terminal color configuration
9 | int lightColors(char *dest) {
10 | memset(dest, 0, DEST_SIZE);
11 |
12 | for(int i = 0; i < 8; ++i)
13 | sprintf(dest + strlen(dest), "\033[%s%dm%s", _col_background ? "10" : "9", i, config.col_block_str);
14 |
15 | strcat(dest, "\033[0m");
16 |
17 | return RET_OK;
18 | }
19 |
--------------------------------------------------------------------------------
/src/info/local_ip.c:
--------------------------------------------------------------------------------
1 | #include "info.h"
2 | #include "../config/config.h"
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | // get all local ips
11 | int localIp(char *dest) {
12 | struct ifaddrs *addrs = NULL;
13 | bool done = false;
14 | int buf_size = DEST_SIZE;
15 |
16 | getifaddrs(&addrs);
17 |
18 | struct ifaddrs *first = addrs;
19 |
20 | while(addrs) {
21 | // checking if the ip is valid
22 | if(addrs->ifa_addr && addrs->ifa_addr->sa_family == AF_INET) {
23 | // filtering out docker or localhost ips
24 | if((strcmp(addrs->ifa_name, "lo") != 0 || _loc_localhost) && (strcmp(addrs->ifa_name, "docker0") != 0 || _loc_docker)) {
25 | struct sockaddr_in *pAddr = (struct sockaddr_in *)addrs->ifa_addr;
26 |
27 | // saving it to the list of interfaces
28 | snprintf(dest, buf_size, "%s%s (%s)", done ? ", " : "", inet_ntoa(pAddr->sin_addr), addrs->ifa_name);
29 | dest += strlen(dest);
30 | buf_size -= strlen(dest);
31 | done = true;
32 | }
33 | }
34 |
35 | addrs = addrs->ifa_next;
36 | }
37 |
38 | freeifaddrs(first);
39 |
40 | if(done)
41 | return RET_OK;
42 | else
43 | return ERR_NO_INFO;
44 | }
45 |
--------------------------------------------------------------------------------
/src/info/login_shell.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "info.h"
5 | #include "../config/config.h"
6 | #include "../utils/wrappers.h"
7 |
8 | // get the current login shell
9 | int loginShell(char *dest) {
10 | char *buf = getenv("SHELL");
11 |
12 | if(buf != NULL) {
13 | safeStrncpy(dest, _shell_path ? buf : basename(buf), DEST_SIZE);
14 | return RET_OK;
15 | }
16 |
17 | return ERR_NO_INFO;
18 | }
19 |
--------------------------------------------------------------------------------
/src/info/memory.c:
--------------------------------------------------------------------------------
1 | #include "info.h"
2 | #include "../utils/queue.h"
3 | #include "../config/config.h"
4 |
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | #ifdef __APPLE__
11 | #include "../macos/macos_infos.h"
12 | #else
13 | #include
14 | #endif // __APPLE__
15 |
16 | // get used and total memory
17 | int memory(char *dest) {
18 | #ifdef __APPLE__
19 | unsigned long usedram = (unsigned long)usedMemSize();
20 | unsigned long totalram = (unsigned long)systemMemSize();
21 |
22 | if(usedram == 0 || totalram == 0) {
23 | return ERR_NO_INFO;
24 | }
25 |
26 | snprintf(dest, DEST_SIZE, "%lu MiB / %lu MiB", usedram / 1048576, totalram / 1048576);
27 |
28 | #else
29 | struct sysinfo info;
30 | if(sysinfo(&info))
31 | return ERR_NO_INFO;
32 |
33 | unsigned long totalram = info.totalram / 1024;
34 | unsigned long freeram = info.freeram / 1024;
35 | // unsigned long sharedram = info.sharedram / 1024;
36 |
37 | FILE *fp = fopen("/proc/meminfo", "r");
38 |
39 | if(fp == NULL)
40 | return ERR_NO_FILE;
41 |
42 | char buf[DEST_SIZE];
43 | char *cachedram = buf;
44 |
45 | readAfterSequence(fp, "Cached:", buf, DEST_SIZE);
46 | fclose(fp);
47 |
48 | if(buf[0] == 0)
49 | return ERR_PARSING;
50 | cachedram += 2;
51 |
52 | char *end = strstr(cachedram, " kB");
53 |
54 | if(end == NULL)
55 | return ERR_PARSING + 0x10;
56 |
57 | *end = 0;
58 |
59 | unsigned long usedram = totalram - freeram - atol(cachedram);
60 | // usedram -= sharedram;
61 |
62 | snprintf(dest, DEST_SIZE, "%lu MiB / %lu MiB", usedram / 1024, totalram / 1024);
63 | #endif
64 |
65 | if(_mem_perc) {
66 | const size_t len = DEST_SIZE - strlen(dest);
67 | char perc[len];
68 |
69 | snprintf(perc, len, " (%lu%%)", (usedram * 100) / totalram);
70 | strcat(dest, perc);
71 | }
72 |
73 | return RET_OK;
74 | }
75 |
--------------------------------------------------------------------------------
/src/info/os.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "info.h"
6 | #include "../config/config.h"
7 | #include "../utils/queue.h"
8 | #include "../utils/wrappers.h"
9 |
10 | // print the operating system name and architecture (uname -m)
11 | int os(char *dest) {
12 | struct utsname name;
13 | uname(&name);
14 |
15 | #ifdef __APPLE__
16 | if(_os_arch)
17 | snprintf(dest, DEST_SIZE, "macOS (%s)", name.machine);
18 | else
19 | safeStrncpy(dest, "macOS", DEST_SIZE);
20 | #else
21 | #ifdef __ANDROID__
22 | char version[16];
23 | char *args[] = {"getprop", "ro.build.version.release", NULL};
24 | execCmd(version, 16, args);
25 |
26 | if(_os_arch)
27 | snprintf(dest, DEST_SIZE, "Android %s%s(%s)", version, version[0] ? " " : "", name.machine);
28 | else
29 | snprintf(dest, DEST_SIZE, "Android %s", version);
30 | #else
31 | FILE *fp = fopen("/etc/os-release", "r");
32 | if(fp == NULL) {
33 | fp = fopen("/usr/lib/os-release", "r");
34 | if(fp == NULL)
35 | return ERR_NO_FILE;
36 | }
37 |
38 | char buf[64];
39 | char *os_name = buf;
40 | char *end;
41 |
42 | readAfterSequence(fp, "PRETTY_NAME", buf, 64);
43 | fclose(fp);
44 |
45 | if(buf[0] == 0)
46 | return ERR_PARSING;
47 |
48 | if((end = strchr(os_name, '\n')) == 0)
49 | return ERR_PARSING + 0x10;
50 | *end = 0;
51 |
52 | // sometimes we have something like `ID="distro"`. yeah its stupid
53 | if(os_name[0] == '"' || os_name[0] == '\'')
54 | ++os_name;
55 |
56 | if((end = strchr(os_name, '"')) == 0)
57 | end = strchr(os_name, '\'');
58 | if(end)
59 | *end = 0;
60 |
61 | if(_os_arch)
62 | snprintf(dest, DEST_SIZE, "%s (%s)", os_name, name.machine);
63 | else
64 | safeStrncpy(dest, os_name, DEST_SIZE);
65 | #endif // __ANDROID__
66 | #endif // __APPLE__
67 |
68 | return RET_OK;
69 | }
70 |
--------------------------------------------------------------------------------
/src/info/packages.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | // just here to stop vscode from complaining about DT_DIR
7 | #ifndef __USE_MISC
8 | #define __USE_MISC
9 | #endif
10 |
11 | #include
12 | #include
13 | #include
14 |
15 | #include "info.h"
16 | #include "../config/config.h"
17 | #include "../optdeps/optdeps.h"
18 | #include "../utils/wrappers.h"
19 |
20 | /*
21 | * I know that I could probably use specific libraries (like ALPM
22 | * or some RPM stuff) and add them as optional dependencies, however:
23 | * - I'm too lazy to do that
24 | * - that would be way slower than just counting directories
25 | */
26 |
27 | // get the number of installed packages
28 | int packages(char *dest) {
29 | dest[0] = 0;
30 | char buf[DEST_SIZE] = "", str[128] = "";
31 | DIR *dir;
32 | struct dirent *entry;
33 | unsigned count = 0;
34 | bool done = false;
35 |
36 | #ifdef __linux__ // package managers that won't run on macOS
37 | FILE *fp;
38 | char *prefix = getenv("PREFIX");
39 | char path[256];
40 |
41 | path[0] = 0;
42 | if(prefix)
43 | safeStrncpy(path, prefix, 256);
44 | strncat(path, "/var/lib/pacman/local", 255 - strlen(path));
45 | if(_pkg_pacman && (dir = opendir(path)) != NULL) {
46 | while((entry = readdir(dir)) != NULL)
47 | if(entry->d_type == DT_DIR && entry->d_name[0] != '.')
48 | ++count;
49 | closedir(dir);
50 |
51 | if(count) {
52 | snprintf(dest, DEST_SIZE, "%u%s", count, _pkg_mgr ? " (pacman)" : "");
53 | done = true;
54 | }
55 | }
56 |
57 | path[0] = 0;
58 | if(prefix)
59 | safeStrncpy(path, prefix, 256);
60 | strncat(path, "/var/lib/dpkg/status", 255 - strlen(path));
61 | if(_pkg_dpkg && (fp = fopen(path, "r")) != NULL) {
62 | char line[512];
63 | int count = 0;
64 |
65 | while(fgets(line, sizeof(line), fp)) {
66 | // check if the line starts with "Package:"
67 | if(strncmp(line, "Package:", 8) == 0) {
68 | ++count;
69 | }
70 | }
71 | fclose(fp);
72 |
73 | if(count) {
74 | snprintf(buf, DEST_SIZE, "%u%s", count, _pkg_mgr ? " (dpkg)" : "");
75 | done = true;
76 | strncat(dest, buf, DEST_SIZE - strlen(dest));
77 | }
78 | }
79 |
80 | path[0] = 0;
81 | if(prefix)
82 | safeStrncpy(path, prefix, 256);
83 | strncat(path, "/var/lib/rpm/rpmdb.sqlite", 255 - strlen(path));
84 | if(_pkg_rpm && access(path, F_OK) == 0) {
85 | sqlite3 *db;
86 | sqlite3_stmt *stmt;
87 | int count = 0;
88 |
89 | if(sqlite3_open(path, &db) != SQLITE_OK)
90 | goto skip;
91 | if(sqlite3_prepare_v2(db, "SELECT count(*) FROM Packages", -1, &stmt, NULL) != SQLITE_OK) {
92 | sqlite3_close(db);
93 | goto skip;
94 | }
95 |
96 | if(sqlite3_step(stmt) == SQLITE_ROW) {
97 | count = sqlite3_column_int(stmt, 0);
98 |
99 | if(count > 0) {
100 | snprintf(buf, DEST_SIZE - strlen(buf), "%s%s%s", done ? ", " : "", str, _pkg_mgr ? " (rpm)" : "");
101 | done = true;
102 | strncat(dest, buf, DEST_SIZE - strlen(dest));
103 | }
104 | }
105 |
106 | sqlite3_finalize(stmt);
107 | sqlite3_close(db);
108 |
109 | skip:;
110 | }
111 |
112 | path[0] = 0;
113 | if(prefix)
114 | safeStrncpy(path, prefix, 256);
115 | strncat(path, "/var/lib/flatpak/runtime", 255 - strlen(path));
116 | if(_pkg_flatpak && (dir = opendir(path)) != NULL) {
117 | count = 0;
118 | while((entry = readdir(dir)) != NULL)
119 | if(entry->d_type == DT_DIR && entry->d_name[0] != '.')
120 | ++count;
121 | closedir(dir);
122 |
123 | if(count) {
124 | snprintf(buf, DEST_SIZE - strlen(buf), "%s%u%s", done ? ", " : "", count, _pkg_mgr ? " (flatpak)" : "");
125 | done = true;
126 | strncat(dest, buf, DEST_SIZE - strlen(dest));
127 | }
128 | }
129 |
130 | path[0] = 0;
131 | if(prefix)
132 | safeStrncpy(path, prefix, 256);
133 | strncat(path, "/var/snap", 255 - strlen(path));
134 | if(_pkg_snap && (dir = opendir(path)) != NULL) {
135 | count = 0;
136 | while((entry = readdir(dir)) != NULL)
137 | if(entry->d_type == DT_DIR && entry->d_name[0] != '.')
138 | ++count;
139 | closedir(dir);
140 |
141 | if(count) {
142 | snprintf(buf, DEST_SIZE - strlen(buf), "%s%u%s", done ? ", " : "", count, _pkg_mgr ? " (snap)" : "");
143 | done = true;
144 | strncat(dest, buf, DEST_SIZE - strlen(dest));
145 | }
146 | }
147 | #endif
148 |
149 | if(_pkg_brew && (binaryInPath("brew"))) {
150 | char *args[] = {"brew", "--cellar", NULL};
151 | execCmd(str, 16, args);
152 |
153 | if(str[0]) {
154 | if((dir = opendir(str)) != NULL) {
155 | count = 0;
156 |
157 | while((entry = readdir(dir)) != NULL)
158 | if(entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
159 | ++count;
160 | closedir(dir);
161 |
162 | if(count) {
163 | snprintf(buf, DEST_SIZE, "%s%u%s", done ? ", " : "", count, _pkg_mgr ? " (brew)" : "");
164 | done = true;
165 | strncat(dest, buf, DEST_SIZE - strlen(dest));
166 | }
167 | }
168 | }
169 | }
170 |
171 | if(_pkg_pip && binaryInPath("pip")) {
172 | char *args[] = {"sh", "-c", "pip list 2>/dev/null | wc -l", NULL};
173 | execCmd(str, 16, args);
174 |
175 | if(str[0] != '0' && str[0]) {
176 | snprintf(buf, DEST_SIZE - strlen(buf), "%s%d%s", done ? ", " : "", atoi(str) - 2, _pkg_mgr ? " (pip)" : "");
177 | done = true;
178 | strncat(dest, buf, DEST_SIZE - strlen(dest));
179 | }
180 | }
181 |
182 | if(done)
183 | return RET_OK;
184 | else
185 | return ERR_NO_INFO;
186 | }
187 |
--------------------------------------------------------------------------------
/src/info/public_ip.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "info.h"
9 | #include "../utils/wrappers.h"
10 |
11 | // Also, this doesn't seem to be working with the Wifi of a Hotel I'm currently staying in
12 | // I wonder why. There seems to be no IP adress in buf, but using curl works just fine.
13 | // I should probably reimplement curl as optdep for fallback, idk
14 | int puts(const char *);
15 | // get the current public ip
16 | int publicIp(char *dest) {
17 | // https://stackoverflow.com/a/65362666 - thanks dbush
18 |
19 | struct addrinfo hints = {0}, *addrs;
20 | hints.ai_family = AF_INET;
21 | hints.ai_socktype = SOCK_STREAM;
22 | hints.ai_protocol = 0;
23 |
24 | // using this as it is faster than ident.me
25 | if(getaddrinfo("whatismyip.akamai.com", "80", &hints, &addrs)) {
26 | return ERR_NO_INFO;
27 | }
28 |
29 | int socket_fd = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
30 | if(socket_fd == -1) {
31 | freeaddrinfo(addrs);
32 | return ERR_NO_INFO + 0x10;
33 | }
34 |
35 | if(connect(socket_fd, addrs->ai_addr, addrs->ai_addrlen) == -1) {
36 | close(socket_fd);
37 | freeaddrinfo(addrs);
38 | return ERR_NO_INFO + 0x20;
39 | }
40 |
41 | char cmd[] = "GET / HTTP/1.1\nHost: whatismyip.akamai.com\n\n";
42 | if(send(socket_fd, cmd, strlen(cmd), 0) == -1) {
43 | close(socket_fd);
44 | freeaddrinfo(addrs);
45 | return ERR_NO_INFO + 0x30;
46 | }
47 |
48 | char buf[1024] = "";
49 | if(recv(socket_fd, buf, sizeof(buf), 0) == -1) {
50 | close(socket_fd);
51 | freeaddrinfo(addrs);
52 | return ERR_NO_INFO + 0x40;
53 | }
54 |
55 | close(socket_fd);
56 | freeaddrinfo(addrs);
57 |
58 | /* buf should now look like this:
59 | * """
60 | * HTTP/1.1 200 OK
61 | * [...]
62 | * [...]
63 | *
64 | * 123.123.123.123
65 | * """
66 | */
67 | char *start = buf, *end;
68 | end = strchr(start, '\n');
69 | if(strncmp(start, "HTTP/1.1 200 OK", end - start - 1) != 0)
70 | return ERR_NO_INFO + 0x50;
71 |
72 | start = strstr(start, "\n\r\n");
73 | if(start == NULL)
74 | return ERR_PARSING;
75 |
76 | start += 3;
77 |
78 | safeStrncpy(dest, start, DEST_SIZE);
79 |
80 | return RET_OK;
81 | }
82 |
--------------------------------------------------------------------------------
/src/info/pwd.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "info.h"
6 | #include "../config/config.h"
7 | #include "../utils/wrappers.h"
8 |
9 | // get the current working directory
10 | int pwd(char *dest) {
11 | #ifdef __APPLE__
12 | char *pwd = getcwd(NULL, DEST_SIZE);
13 | #else
14 | char *pwd = getcwd(NULL, 0);
15 | #endif // __APPLE__
16 |
17 | if(pwd == NULL)
18 | return ERR_NO_INFO;
19 |
20 | safeStrncpy(dest, _pwd_path ? pwd : basename(pwd), DEST_SIZE);
21 | free(pwd);
22 |
23 | return RET_OK;
24 | }
25 |
--------------------------------------------------------------------------------
/src/info/shell.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #ifdef __linux__
5 | #include
6 | #include
7 | #endif // __linux__
8 |
9 | #include "info.h"
10 | #include "../config/config.h"
11 | #include "../utils/wrappers.h"
12 |
13 | // get the parent process name (usually the shell)
14 | int shell(char *dest) {
15 | #ifdef __linux__
16 | char path[32];
17 |
18 | sprintf(path, "/proc/%d/cmdline", getppid());
19 |
20 | FILE *fp = fopen(path, "r");
21 | if(fp) {
22 | char shell[DEST_SIZE];
23 | shell[fread(shell, 1, DEST_SIZE - 1, fp)] = 0;
24 | fclose(fp);
25 |
26 | if(shell[0] == '-') { // cmdline is "-bash" when login shell
27 | safeStrncpy(dest, _shell_path ? shell + 1 : basename(shell + 1), DEST_SIZE);
28 | return RET_OK;
29 | }
30 |
31 | safeStrncpy(dest, _shell_path ? shell : basename(shell), DEST_SIZE);
32 | return RET_OK;
33 | }
34 | #endif
35 |
36 | char *shell = getenv("SHELL");
37 | if(shell == NULL)
38 | return ERR_NO_INFO;
39 | if(shell[0] == 0)
40 | return ERR_NO_INFO + 0x10;
41 |
42 | safeStrncpy(dest, _shell_path ? shell : basename(shell), DEST_SIZE);
43 |
44 | return RET_OK;
45 | }
46 |
--------------------------------------------------------------------------------
/src/info/swap.c:
--------------------------------------------------------------------------------
1 | #include "info.h"
2 | #include "../utils/queue.h"
3 | #include "../config/config.h"
4 |
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | #ifndef __APPLE__
11 | #include
12 | #endif // __APPLE__
13 |
14 | // get used and total swap
15 | int swap(char *dest) {
16 | #ifdef __APPLE__
17 | // don't really know how to do it and am too lazy to research it, so...
18 | (void)dest;
19 | return ERR_UNSUPPORTED;
20 | #else
21 | struct sysinfo info;
22 | if(sysinfo(&info))
23 | return ERR_NO_INFO;
24 |
25 | unsigned long totalswap = info.totalswap / 1024;
26 | unsigned long freeswap = info.freeswap / 1024;
27 |
28 | if(totalswap * freeswap == 0) // one or the other
29 | return ERR_NO_INFO;
30 |
31 | unsigned long usedswap = totalswap - freeswap;
32 |
33 | snprintf(dest, DEST_SIZE, "%lu MiB / %lu MiB", usedswap / 1024, totalswap / 1024);
34 |
35 | if(_swap_perc) {
36 | const size_t len = DEST_SIZE - strlen(dest);
37 | char perc[len];
38 |
39 | snprintf(perc, len, " (%lu%%)", (usedswap * 100) / totalswap);
40 | strcat(dest, perc);
41 | }
42 | #endif
43 |
44 | return RET_OK;
45 | }
46 |
--------------------------------------------------------------------------------
/src/info/term.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "info.h"
6 | #include "../config/config.h"
7 | #include "../utils/wrappers.h"
8 |
9 | // get the current terminal
10 | int term(char *dest) {
11 | // TODO: print terminal version (using env variables, parsing --version outputs, ...)
12 | const char *terminal = NULL;
13 |
14 | const char *terminals[][2] = {// {"ENVIRONMENT_VARIABLE", "terminal"},
15 | {"ALACRITTY_WINDOW_ID", "Alacritty"}, {"KITTY_PID", "Kitty"}, {"VSCODE_INJECTION", "VS Code"},
16 | {"TERMUX_VERSION", "Termux"}, {"KONSOLE_VERSION", "Konsole"}, {"GNOME_TERMINAL_SCREEN", "GNOME Terminal"},
17 | {"WT_SESSION", "Windows Terminal"}, {"TERMINATOR_UUID", "Terminator"}};
18 |
19 | for(size_t i = 0; i < sizeof(terminals) / sizeof(terminals[0]); ++i)
20 | if(getenv(terminals[i][0]))
21 | terminal = terminals[i][1];
22 |
23 | if(terminal == NULL) {
24 | terminal = getenv("TERM_PROGRAM");
25 | if(terminal == NULL)
26 | terminal = getenv("TERM");
27 | if(terminal == NULL)
28 | return ERR_NO_INFO;
29 |
30 | if(strcmp(terminal, "xterm-kitty") == 0)
31 | terminal = "Kitty";
32 | else if(strcmp(terminal, "alacritty") == 0)
33 | terminal = "Alacritty";
34 | else if(strcmp(terminal, "Apple_Terminal") == 0)
35 | terminal = "Apple Terminal";
36 | }
37 |
38 | if(_term_ssh && getenv("SSH_CONNECTION"))
39 | snprintf(dest, DEST_SIZE, "%s (SSH)", terminal);
40 | else
41 | safeStrncpy(dest, terminal, DEST_SIZE);
42 |
43 | return RET_OK;
44 | }
45 |
--------------------------------------------------------------------------------
/src/info/uptime.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #ifdef __APPLE__
5 | #include "../macos/bsdwrap.h"
6 | #else
7 | #include
8 | #endif // __APPLE__
9 |
10 | #include "info.h"
11 | #include "../utils/wrappers.h"
12 |
13 | // print the current uptime
14 | int uptime(char *dest) {
15 | #ifdef __APPLE__
16 | struct timeval boottime;
17 | int error;
18 | long uptime;
19 | error = sysctlWrap(&boottime, sizeof(boottime), CTL_KERN, KERN_BOOTTIME);
20 |
21 | if(error < 0)
22 | return ERR_NO_INFO;
23 |
24 | time_t boot_seconds = boottime.tv_sec;
25 | time_t current_seconds = time(NULL);
26 |
27 | uptime = (long)difftime(current_seconds, boot_seconds);
28 | #else
29 | struct sysinfo info;
30 | if(sysinfo(&info))
31 | return ERR_NO_INFO;
32 |
33 | const long uptime = info.uptime;
34 | #endif // __APPLE__
35 |
36 | long days = uptime / 86400;
37 | long hours = (uptime / 3600) - (days * 24);
38 | long mins = (uptime / 60) - (days * 1440) - (hours * 60);
39 |
40 | char result[DEST_SIZE] = "";
41 | char str[24] = "";
42 |
43 | if(days) {
44 | snprintf(str, 24, "%ldd%c", days, hours || mins ? ' ' : 0); // print the number of days passed if more than 0
45 | strcat(result, str);
46 | }
47 | if(hours) {
48 | snprintf(str, 24, "%ldh%c", hours, mins ? ' ' : 0); // print the number of days passed if more than 0
49 | strcat(result, str);
50 | }
51 | if(mins) {
52 | snprintf(str, 24, "%ldm", mins); // print the number of minutes passed if more than 0
53 | strcat(result, str);
54 | } else if(uptime < 60) {
55 | snprintf(str, 24, "%lds", uptime); // print the number of seconds passed if less than 60
56 | strcat(result, str);
57 | }
58 |
59 | safeStrncpy(dest, result, DEST_SIZE);
60 |
61 | return RET_OK;
62 | }
63 |
--------------------------------------------------------------------------------
/src/info/user.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "info.h"
5 | #include "../utils/wrappers.h"
6 |
7 | // print the current user
8 | int user(char *dest) {
9 | struct passwd *pw;
10 |
11 | unsigned uid = geteuid();
12 | if((int)uid == -1) {
13 | // couldn't get UID
14 | return ERR_NO_INFO;
15 | }
16 |
17 | pw = getpwuid(uid);
18 |
19 | safeStrncpy(dest, pw->pw_name, DEST_SIZE);
20 |
21 | return RET_OK;
22 | }
23 |
--------------------------------------------------------------------------------
/src/macos/bsdwrap.c:
--------------------------------------------------------------------------------
1 | #include "bsdwrap.h"
2 | #include "../utils/return.h"
3 |
4 | #ifdef __APPLE__
5 |
6 | int sysctlWrap(void *out, size_t outsize, int domain, int field) {
7 | int mib[] = {domain, field};
8 | int error = sysctl(mib, 2, out, &outsize, NULL, 0);
9 |
10 | if(error < 0)
11 | return ERR_NO_INFO;
12 |
13 | return RET_OK;
14 | }
15 |
16 | #endif // __APPLE__
17 |
--------------------------------------------------------------------------------
/src/macos/bsdwrap.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifdef __APPLE__
4 |
5 | #include
6 | #include
7 |
8 | /*
9 | * Header for BSD standard system-querying
10 | * functions (also applicable to macos).
11 | */
12 |
13 | /*
14 | * This is a wrapper function over the fairly
15 | * cryptic BSD `sysctl` function.
16 | *
17 | * Note that `out` is meant to be casted by the
18 | * user as it can return various types depending on the query.
19 | * If the type is _slightly_ incorrect, the function will fail.
20 | *
21 | * The function returns 0 if the query was successful,
22 | * or -1 if the query failed.
23 | *
24 | * To find the expected values for `domain` and `field`,
25 | * refer to the `sysctl` man pages.
26 | *
27 | * ex. For querying total memory size.
28 | *
29 | * ```c
30 | * uint64_t size;
31 | * size_t len = sizeof(uin64_t);
32 | * sysctlWrap(&size, &len,
33 | * CTL_HW, // Query the hardware domain.
34 | * HW_MEMSIZE); // Get memory size from the hardware domain.
35 | * ```
36 | */
37 |
38 | int sysctlWrap(void *out, size_t outsize, int domain, int field);
39 |
40 | #endif // __APPLE__
41 |
--------------------------------------------------------------------------------
/src/macos/macos_gpu_string.m:
--------------------------------------------------------------------------------
1 | #include "macos_infos.h"
2 |
3 | #import // this lets us know when to use deprecated apis
4 | #import
5 | #import
6 |
7 | char *getGpuString(void) {
8 | CFMutableDictionaryRef dict = IOServiceMatching("IOPCIDevice");
9 | io_iterator_t iter;
10 | int success;
11 | const char *result = NULL;
12 |
13 | #if __OSX_AVAILABLE_STARTING(__MAC_12_0,__IPHONE_NA)
14 |
15 | mach_port_t port = kIOMainPortDefault;
16 |
17 | #else
18 | #pragma clang diagnostic push
19 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
20 |
21 | mach_port_t port = kIOMasterPortDefault; // kIOMasterPortDefault has been deprecated since macOS Monterey
22 |
23 | #pragma clang diagnostic pop
24 |
25 | #endif
26 |
27 | success = IOServiceGetMatchingServices(port, dict, &iter);
28 | if(success != kIOReturnSuccess)
29 | return NULL;
30 |
31 | io_registry_entry_t entry;
32 |
33 | while((entry = IOIteratorNext(iter))) {
34 | CFMutableDictionaryRef services;
35 | success = IORegistryEntryCreateCFProperties(entry, &services, kCFAllocatorDefault, kNilOptions);
36 | if(success != kIOReturnSuccess) {
37 | IOObjectRelease(entry);
38 | continue;
39 | }
40 |
41 | const void *gpu_model = CFDictionaryGetValue(services, @"model");
42 | if(gpu_model != nil) {
43 | if(CFGetTypeID(gpu_model) == CFDataGetTypeID()) {
44 | NSString *modelName = [[NSString alloc] initWithData:
45 | (NSData *)gpu_model encoding:NSASCIIStringEncoding];
46 |
47 | result = [modelName cStringUsingEncoding:NSUTF8StringEncoding];
48 | }
49 | }
50 |
51 | CFRelease(services);
52 | IOObjectRelease(entry);
53 | }
54 |
55 | IOObjectRelease(iter);
56 |
57 | return (char*)result;
58 | }
59 |
--------------------------------------------------------------------------------
/src/macos/macos_infos.c:
--------------------------------------------------------------------------------
1 | #include "macos_infos.h"
2 | #include "../utils/return.h"
3 |
4 | /* STATIC HELPERS */
5 |
6 | #ifdef __APPLE__
7 |
8 | const static vm_size_t FALLBACK_PAGE_SIZE = 4096;
9 |
10 | static vm_size_t page_size(mach_port_t host) {
11 | vm_size_t page_size;
12 | int error;
13 |
14 | error = host_page_size(host, &page_size);
15 |
16 | return (error < 0) ? page_size : FALLBACK_PAGE_SIZE;
17 | }
18 |
19 | /*
20 | * Original source:
21 | * https://opensource.apple.com/source/system_cmds/system_cmds-496/vm_stat.tproj/vm_stat.c.auto.html
22 | */
23 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
24 | static int get_stats(struct vm_statistics *stat, mach_port_t host) {
25 | int error;
26 |
27 | unsigned count = HOST_VM_INFO_COUNT;
28 | error = host_statistics(host, HOST_VM_INFO, (host_info_t)stat, &count);
29 |
30 | if(error != KERN_SUCCESS)
31 | return error;
32 |
33 | return RET_OK;
34 | }
35 | #else
36 | static int get_stats(struct vm_statistics64 *stat, mach_port_t host) {
37 | int error;
38 |
39 | unsigned count = HOST_VM_INFO64_COUNT;
40 | error = host_statistics64(host, HOST_VM_INFO64, (host_info64_t)stat, &count);
41 |
42 | if(error != KERN_SUCCESS)
43 | return error;
44 |
45 | return RET_OK;
46 | }
47 | #endif
48 |
49 | /* EXPORTS */
50 |
51 | bytes_t systemMemSize(void) {
52 | uint64_t size;
53 | int error;
54 |
55 | error = sysctlWrap(&size, sizeof(uint64_t), CTL_HW, HW_MEMSIZE);
56 |
57 | // Since no computer should have 0 bytes of memory,
58 | // 0 indicates failure.
59 | if(error < 0)
60 | return RET_OK;
61 |
62 | return size;
63 | }
64 |
65 | bytes_t usedMemSize(void) {
66 | #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
67 | pages_t active, wired, inactive;
68 | mach_port_t host = mach_host_self();
69 |
70 | struct vm_statistics vm_stat;
71 | if(get_stats(&vm_stat, host) < 0)
72 | return RET_OK;
73 |
74 | active = vm_stat.active_count;
75 | wired = vm_stat.wire_count;
76 | inactive = vm_stat.inactive_count;
77 |
78 | return (active + wired + inactive) * page_size(host);
79 | #else
80 | pages_t internal, wired, compressed;
81 | mach_port_t host = mach_host_self();
82 |
83 | struct vm_statistics64 vm_stat;
84 | if(get_stats(&vm_stat, host) < 0)
85 | return RET_OK;
86 |
87 | internal = vm_stat.internal_page_count - vm_stat.purgeable_count;
88 | wired = vm_stat.wire_count;
89 | compressed = vm_stat.compressor_page_count;
90 |
91 | return (internal + wired + compressed) * page_size(host);
92 | #endif
93 | }
94 |
95 | #endif // __APPLE__
96 |
--------------------------------------------------------------------------------
/src/macos/macos_infos.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifdef __APPLE__
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #include "bsdwrap.h"
14 |
15 | typedef uint64_t bytes_t;
16 | typedef uint64_t pages_t;
17 |
18 | char *getGpuString(void);
19 |
20 | /*
21 | * Gets the used memory int
22 | */
23 | bytes_t usedMemSize(void);
24 |
25 | bytes_t systemMemSize(void);
26 |
27 | #endif // __APPLE__
28 |
--------------------------------------------------------------------------------
/src/main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "config/config.h"
10 | #include "info/info.h"
11 | #include "utils/logos.h"
12 | #include "utils/queue.h"
13 | #include "utils/return.h"
14 | #include "utils/utils.h"
15 | #include "utils/wrappers.h"
16 |
17 | #ifdef HAVE_VERSION_H
18 | #include "version.h" // generated by meson - defines COMMIT and VERSION
19 | #else
20 | #define VERSION "[UNKNOWN]"
21 | #define COMMIT "[UNKNOWN]"
22 | #endif // HAVE_VERSION_H
23 |
24 | // idk hy but this is sometimes not defined
25 | #ifndef HOST_NAME_MAX
26 | #ifdef _POSIX_HOST_NAME_MAX
27 | #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
28 | #else
29 | #define HOST_NAME_MAX 255
30 | #endif
31 | #endif
32 |
33 | // Not sure if this makes sense
34 | #ifndef LOGIN_NAME_MAX
35 | #define LOGIN_NAME_MAX HOST_NAME_MAX
36 | #endif
37 |
38 | // TODO:
39 | /*
40 | * print de, shell and terminal versions
41 | * Windows support? *BSD support?
42 | * make ascii dynamically use the available space (aka line by line)
43 | * start using gtk for theme and icons
44 | * display resolution
45 | * storage
46 | * steam installed "packages" (off by default)
47 | * cpu temp (off by default)
48 | * rewrite config parsing and make it decent (check rewrite-config-parsing branch)
49 | * write manpage
50 | * fix writing in the previous block when fread returns 0
51 | */
52 |
53 | // This contains the default config values
54 | struct SConfig config = {
55 | // Default values for boolean options (least to most significant bit)
56 | // 0111 0101 1111 1110 1111 1001 0110 ...
57 | .boolean_options = 0x69f7fae,
58 |
59 | .logo = NULL,
60 | .color = "",
61 | .dash = ": ",
62 | .separator = "-",
63 | .spacing = 5,
64 |
65 | .gpu_index = 0,
66 | .date_format = "%02d/%02d/%d %02d:%02d:%02d",
67 | .col_block_str = " ",
68 |
69 | .separator_prefix = "",
70 | .spacing_prefix = "",
71 | .title_prefix = "",
72 | .user_prefix = "User",
73 | .hostname_prefix = "Hostname",
74 | .uptime_prefix = "Uptime",
75 | .os_prefix = "OS",
76 | .kernel_prefix = "Kernel",
77 | .desktop_prefix = "Desktop",
78 | .gtk_theme_prefix = "Theme",
79 | .icon_theme_prefix = "Icons",
80 | .cursor_theme_prefix = "Cursor",
81 | .shell_prefix = "Shell",
82 | .login_shell_prefix = "Login",
83 | .term_prefix = "Terminal",
84 | .pkg_prefix = "Packages",
85 | .host_prefix = "Host",
86 | .bios_prefix = "BIOS",
87 | .cpu_prefix = "CPU",
88 | .gpu_prefix = "GPU",
89 | .mem_prefix = "Memory",
90 | .swap_prefix = "Swap",
91 | .pub_prefix = "Public IP",
92 | .loc_prefix = "Local IP",
93 | .pwd_prefix = "Directory",
94 | .date_prefix = "Date",
95 | .bat_prefix = "Battery",
96 | .colors_prefix = "",
97 | .light_colors_prefix = "",
98 | };
99 |
100 | int main(int argc, char **argv) {
101 | // are the following command line args used?
102 | bool asking_help = false;
103 | bool use_config = true;
104 | bool print_logo = true;
105 | int asking_color = 0;
106 | int asking_bold = 0;
107 | int asking_logo = 0;
108 | int asking_align = 0;
109 |
110 | // these store either the default values or the ones defined in the config
111 | // they are needed to know what is used if no arguments are given (for --help)
112 | bool default_bold = _bold;
113 | char default_color[8] = "";
114 | char default_logo[16] = "";
115 |
116 | // the default config file is ~/.config/albafetch.conf
117 | char config_file[LOGIN_NAME_MAX + 64] = "";
118 | // path of a custom ascii art
119 | char *ascii_file = NULL;
120 | void *ascii_ptr = NULL;
121 |
122 | // parsing the command args
123 | for(int i = 1; i < argc; ++i) {
124 | if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
125 | asking_help = true;
126 | if(strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
127 | puts(VERSION " (built from commit " COMMIT ")");
128 | return RET_OK;
129 | } else if(strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--color") == 0)
130 | asking_color = i + 1;
131 | else if(strcmp(argv[i], "-b") == 0 || strcmp(argv[i], "--bold") == 0)
132 | asking_bold = i + 1;
133 | else if(strcmp(argv[i], "--ascii") == 0) {
134 | if(i + 1 >= argc) { // is there such an arg?
135 | fputs("\033[31m\033[1mERROR\033[0m: --ascii requires an extra argument!\n", stderr);
136 | continue;
137 | }
138 | ascii_file = argv[i + 1];
139 | continue;
140 | } else if(strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--logo") == 0)
141 | asking_logo = i + 1;
142 | else if(strcmp(argv[i], "--align") == 0 || strcmp(argv[i], "-a") == 0)
143 | asking_align = i + 1;
144 | else if(strcmp(argv[i], "--config") == 0 && use_config) {
145 | if(i + 1 >= argc) { // is there such an arg?
146 | fputs("\033[31m\033[1mERROR\033[0m: --config requires an extra argument!\n", stderr);
147 | continue;
148 | }
149 | safeStrncpy(config_file, argv[i + 1], sizeof(config_file));
150 | continue;
151 | } else if(strcmp(argv[i], "--no-logo") == 0)
152 | print_logo = false;
153 | else if(strcmp(argv[i], "--no-config") == 0)
154 | use_config = false;
155 | }
156 |
157 | char data[DEST_SIZE] = ""; // output of each module
158 | char printed[DEST_SIZE * 4] = ""; // line-by-line output of albafetch
159 |
160 | struct SModule *modules = malloc(sizeof(struct SModule));
161 | if(modules == NULL)
162 | return ERR_OOM;
163 | modules->id = NULL;
164 | modules->next = NULL;
165 |
166 | // albafetch will first parse ~/.config/albafetch.conf
167 | // ~/.config/albafetch/albafetch.conf if the former is not found
168 | if(use_config) { // --no-config was not used
169 | bool error = true;
170 |
171 | if(config_file[0] == 0) { // --config was not used, using the default path
172 | char *home = getenv("HOME");
173 | char *config_home = getenv("XDG_CONFIG_HOME");
174 | error = false;
175 |
176 | if(config_home) { // is XDG_CONFIG_HOME set?
177 | snprintf(config_file, sizeof(config_file), "%s/albafetch.conf", config_home);
178 | if(access(config_file, F_OK))
179 | snprintf(config_file, sizeof(config_file), "%s/albafetch/albafetch.conf", config_home);
180 | }
181 | if(home && access(config_file, F_OK)) { // is HOME set?
182 | snprintf(config_file, sizeof(config_file), "%s/.config/albafetch.conf", home);
183 | if(access(config_file, F_OK))
184 | snprintf(config_file, sizeof(config_file), "%s/.config/albafetch/albafetch.conf", home);
185 | }
186 | if(access(config_file, F_OK)) {
187 | strcpy(config_file, "/etc/xdg/albafetch.conf");
188 | }
189 | }
190 |
191 | parseConfig(error, config_file, modules, &ascii_ptr, &default_bold, default_color, default_logo);
192 | }
193 |
194 | if(ascii_file) {
195 | free(ascii_ptr);
196 | ascii_ptr = fileToLogo(ascii_file);
197 | }
198 |
199 | if(asking_logo) { // --logo was used
200 | if(asking_logo < argc) {
201 | bool found = false;
202 |
203 | // find the matching logo
204 | for(size_t i = 0; i < sizeof(logos) / sizeof(logos[0]); ++i)
205 | if(strcmp(logos[i][0], argv[asking_logo]) == 0) {
206 | config.logo = logos[i];
207 | found = true;
208 | }
209 |
210 | if(found == false)
211 | fprintf(stderr, "\033[31m\033[1mERROR\033[0m: invalid logo \"%s\"!\n", argv[asking_logo]);
212 | else
213 | strcpy(config.color, config.logo[1]);
214 | } else
215 | fputs("\033[31m\033[1mERROR\033[0m: --logo requires an extra argument!\n", stderr);
216 | }
217 | if(config.logo == NULL) { // get a logo based on the OS (--logo was not used and no logo was set by the config)
218 | #ifdef __APPLE__
219 | config.logo = logos[1];
220 | #else
221 | #ifdef __ANDROID__
222 | config.logo = logos[2];
223 | #else
224 | config.logo = logos[0];
225 | FILE *fp = fopen("/etc/os-release", "r");
226 |
227 | if(fp == NULL)
228 | fp = fopen("/usr/lib/os-release", "r");
229 |
230 | if(fp != NULL) {
231 | char os_id[48];
232 | // check with a newline first
233 | readAfterSequence(fp, "\nID", os_id, 48);
234 | if(os_id[0] == 0) {
235 | fseek(fp, 0, SEEK_SET);
236 | readAfterSequence(fp, "ID", os_id, 48);
237 | }
238 | fclose(fp);
239 |
240 | char *end = strchr(os_id, '\n');
241 | if(end != NULL)
242 | *end = 0;
243 |
244 | // because Arch Linux ARM has to be special for some reason
245 | // edit: fedora asahi too, yay
246 | if(strcmp(os_id, "archarm") == 0)
247 | os_id[5] = 0;
248 | else if(strcmp(os_id, "fedora-asahi-remix") == 0)
249 | os_id[6] = 0;
250 |
251 | // clean up because of some distros randomly using " or ' when they shouldnt be
252 | if(os_id[0] == '\'' || os_id[0] == '"') {
253 | memmove(os_id, os_id + 1, strlen(os_id));
254 |
255 | end = strchr(os_id, '\'');
256 | if(end == NULL)
257 | end = strchr(os_id, '"');
258 |
259 | if(end != NULL)
260 | *end = 0;
261 | }
262 |
263 | // find the matching logo
264 | for(size_t i = 0; i < sizeof(logos) / sizeof(*logos); ++i)
265 | if(strcmp(logos[i][0], os_id) == 0) {
266 | config.logo = logos[i];
267 | break;
268 | }
269 | }
270 | #endif // __ANDROID__
271 | #endif // __APPLE__
272 |
273 | strcpy(default_logo, config.logo[0]);
274 | strcpy(config.color, config.logo[1]);
275 | }
276 |
277 | if(asking_color) {
278 | if(asking_color < argc) {
279 | const char *colors[][2] = {
280 | {"black", "\033[30m"}, {"red", "\033[31m"}, {"green", "\033[32m"}, {"yellow", "\033[33m"}, {"blue", "\033[34m"},
281 | {"purple", "\033[35m"}, {"cyan", "\033[36m"}, {"gray", "\033[90m"}, {"white", "\033[37m"},
282 | };
283 |
284 | for(int j = 0; j < 9; ++j)
285 | if(strcmp(argv[asking_color], *colors[j]) == 0) {
286 | strcpy(config.color, colors[j][1]);
287 | goto color_done;
288 | }
289 |
290 | fprintf(stderr, "\033[31m\033[1mERROR\033[0m: invalid color \"%s\"!\n", argv[asking_color]);
291 | } else
292 | fputs("\033[31m\033[1mERROR\033[0m: --color requires an extra argument!\n", stderr);
293 |
294 | color_done:;
295 | }
296 |
297 | if(asking_bold) {
298 | if(asking_bold < argc) {
299 | // modifying the 2nd least significant bit of boolean_options
300 | if(strcmp(argv[asking_bold], "on") == 0) {
301 | config.boolean_options |= ((uint64_t)1 << 1);
302 | goto bold_done;
303 | } else if(strcmp(argv[asking_bold], "off") == 0) {
304 | config.boolean_options &= ~((uint64_t)1 << 1);
305 | goto bold_done;
306 | }
307 |
308 | fputs("\033[31m\033[1mERROR\033[0m: --bold should be followed by either \"on\" or \"off\"!\n", stderr);
309 | } else
310 | fputs("\033[31m\033[1mERROR\033[0m: --bold requires an extra argument!\n", stderr);
311 |
312 | bold_done:;
313 | }
314 |
315 | if(asking_help) {
316 | // it won't be used anyway lol
317 | destroyArray(modules);
318 |
319 | printf("%s%salbafetch\033[0m - a system fetch utility\n", config.color, _bold ? "\033[1m" : "");
320 |
321 | printf("\n%s%sFLAGS\033[0m:\n", config.color, _bold ? "\033[1m" : "");
322 |
323 | printf("\t%s%s-h\033[0m,%s%s --help\033[0m:\t Print this help menu and exit\n", config.color, _bold ? "\033[1m" : "", config.color, _bold ? "\033[1m" : "");
324 |
325 | printf("\t%s%s-v\033[0m,%s%s --version\033[0m:\t Print the version and exit\n", config.color, _bold ? "\033[1m" : "", config.color, _bold ? "\033[1m" : "");
326 |
327 | printf("\t%s%s-c\033[0m,%s%s --color\033[0m:\t Change the output color (%s%s\033[0m)\n"
328 | "\t\t\t [\033[30mblack\033[0m, \033[31mred\033[0m, \033[32mgreen\033[0m, \033[33myellow\033[0m,"
329 | " \033[34mblue\033[0m, \033[35mpurple\033[0m, \033[36mcyan\033[0m, \033[90mgray\033[0m,"
330 | " \033[37mwhite\033[0m]\n",
331 | config.color, _bold ? "\033[1m" : "", config.color, _bold ? "\033[1m" : "", default_color[0] ? default_color : config.logo[1],
332 | default_color[0] ? "default" : "logo default");
333 |
334 | printf("\t%s%s-b\033[0m,%s%s --bold\033[0m:\t Specifies if bold should be used in colored parts (default: %s\033[0m)\n"
335 | "\t\t\t [\033[1mon\033[0m, off]\n",
336 | config.color, _bold ? "\033[1m" : "", config.color, _bold ? "\033[1m" : "", default_bold ? "\033[1mon" : "off");
337 |
338 | printf("\t%s%s-l\033[0m,%s%s --logo\033[0m:\t Changes the logo that will be displayed (default: %s)\n"
339 | "\t\t\t [alpine, android, apple, arch, arch_small, debian, endeavouros, fedora, gentoo]\n"
340 | "\t\t\t [linux, linuxmint, mageia, manjaro, neon, nixos, none, parrot, pop, ubuntu, windows]\n",
341 | config.color, _bold ? "\033[1m" : "", config.color, _bold ? "\033[1m" : "", default_logo[0] ? default_logo : "OS Default");
342 |
343 | printf("\t%s%s--ascii\033[0m:\t Specifies a file containing a custom ascii art to use as logo (default: none)\n"
344 | "\t\t\t [path]\n",
345 | config.color, _bold ? "\033[1m" : "");
346 |
347 | printf("\t%s%s-a\033[0m, %s%s--align\033[0m:\t Aligns the infos if set (default: %s)\n"
348 | "\t\t\t [on, off]\n",
349 | config.color, _bold ? "\033[1m" : "", config.color, _bold ? "\033[1m" : "", _align ? "on" : "off");
350 |
351 | printf("\t%s%s--config\033[0m:\t Specifies a custom config (default: ~/.config/albafetch.conf)\n"
352 | "\t\t\t [path]\n",
353 | config.color, _bold ? "\033[1m" : "");
354 |
355 | printf("\t%s%s--no-logo\033[0m:\t Prints the infos without a logo or ascii art\n", config.color, _bold ? "\033[1m" : "");
356 |
357 | printf("\t%s%s--no-config\033[0m:\t Ignores any provided or existing config file\n", config.color, _bold ? "\033[1m" : "");
358 |
359 | printf("\nReport a bug: %s%s\033[4mhttps://github.com/alba4k/albafetch/issues\033[0m\n", config.color, _bold ? "\033[1m" : "");
360 |
361 | return RET_OK;
362 | }
363 |
364 | if(asking_align) {
365 | if(asking_align < argc) {
366 | if(strcmp(argv[asking_align], "on") == 0) {
367 | config.boolean_options |= (uint64_t)1;
368 | goto align_done;
369 | } else if(strcmp(argv[asking_align], "off") == 0) {
370 | config.boolean_options &= ~((uint64_t)1);
371 | goto align_done;
372 | }
373 |
374 | fputs("\033[31m\033[1mERROR\033[0m: --align should be followed by either \"on\" or \"off\"!\n", stderr);
375 | } else
376 | fputs("\033[31m\033[1mERROR\033[0m: --align requires an extra argument!\n", stderr);
377 |
378 | align_done:;
379 | }
380 |
381 | // I am deeply sorry for the code you're about to see - I hope you like spaghetti
382 | unsigned line = 1;
383 | char format[32] = "%s\033[0m%s";
384 |
385 | /* getting the terminal width
386 | * I start by using stdout
387 | * if it is not a terminal (e.g. if the user did albafetch | lolcat) I use stderr
388 | * if stderr doesn't work either, I use stdin (albafetch 2>/dev/null | lolcat)
389 | * now, let's assume the user is a complete moron and redirects everything. Then I just use an "infinite" width
390 | */
391 | struct winsize win;
392 | win.ws_col = 0;
393 | if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &win))
394 | if(ioctl(STDERR_FILENO, TIOCGWINSZ, &win))
395 | ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
396 | if(win.ws_col == 0)
397 | win.ws_col = -1;
398 |
399 | struct SInfo {
400 | char *id; // module identifier
401 | char *label; // module label
402 | int (*func)(char *); // function to run
403 | };
404 | struct SInfo module_table[] = {
405 | // {"identifier", label, func},
406 | {"separator", config.separator_prefix, NULL},
407 | {"space", config.spacing_prefix, NULL},
408 | {"title", config.title_prefix, NULL},
409 | {"user", config.user_prefix, user},
410 | {"hostname", config.hostname_prefix, hostname},
411 | {"uptime", config.uptime_prefix, uptime},
412 | {"os", config.os_prefix, os},
413 | {"kernel", config.kernel_prefix, kernel},
414 | {"desktop", config.desktop_prefix, desktop},
415 | {"gtk_theme", config.gtk_theme_prefix, gtkTheme},
416 | {"icon_theme", config.icon_theme_prefix, iconTheme},
417 | {"cursor_theme", config.cursor_theme_prefix, cursorTheme},
418 | {"shell", config.shell_prefix, shell},
419 | {"login_shell", config.login_shell_prefix, loginShell},
420 | {"term", config.term_prefix, term},
421 | {"packages", config.pkg_prefix, packages},
422 | {"host", config.host_prefix, host},
423 | {"bios", config.bios_prefix, bios},
424 | {"cpu", config.cpu_prefix, cpu},
425 | {"gpu", config.gpu_prefix, gpu},
426 | {"memory", config.mem_prefix, memory},
427 | {"swap", config.swap_prefix, swap},
428 | {"public_ip", config.pub_prefix, publicIp},
429 | {"local_ip", config.loc_prefix, localIp},
430 | {"pwd", config.pwd_prefix, pwd},
431 | {"date", config.date_prefix, date},
432 | {"battery", config.bat_prefix, battery},
433 | {"colors", config.colors_prefix, colors},
434 | {"light_colors", config.light_colors_prefix, lightColors},
435 | };
436 |
437 | // this sets the default module order in case it was not set in a config file
438 | if(modules->next == NULL) {
439 | char *default_order[] = {
440 | "title", "separator", "uptime", "separator", "os", "kernel", "desktop", "shell", "term",
441 | "packages", "separator", "host", "cpu", "gpu", "memory", "space", "colors", "light_colors",
442 | };
443 |
444 | for(size_t i = 0; i < sizeof(default_order) / sizeof(default_order[0]); ++i)
445 | addModule(modules, default_order[i]);
446 | }
447 |
448 | // filling in the linked list (with function pointers and labels) based on the ids
449 | // I prefer doing it here than in addModule as this part only runs when it's needed
450 | for(struct SModule *current = modules->next; current; current = current->next)
451 | for(size_t i = 0; i < sizeof(module_table) / sizeof(module_table[0]); ++i)
452 | if(strcmp(module_table[i].id, current->id) == 0) {
453 | current->label = module_table[i].label;
454 | current->func = module_table[i].func;
455 | }
456 |
457 | if(_align) {
458 | size_t current_len;
459 | asking_align = 0;
460 |
461 | // determining how far the text should be aligned
462 | for(struct SModule *current = modules->next; current; current = current->next) {
463 | current_len = realStrlen(current->label);
464 |
465 | if(current_len > (size_t)asking_align)
466 | asking_align = (int)current_len;
467 | }
468 |
469 | asking_align += (int)realStrlen(config.dash);
470 |
471 | snprintf(format, 32, "%%-%ds\033[0m%%s", asking_align);
472 | }
473 |
474 | // printing every module
475 | for(struct SModule *current = modules->next; current; current = current->next) {
476 | if(strcmp(current->id, "separator") == 0) { // separators are handled differently
477 | if(printed[0] == 0) // first thing being printed
478 | continue;
479 |
480 | // this is the length of the last printed text
481 | const size_t len = realStrlen(printed) - realStrlen(config.separator_prefix) - (print_logo ? realStrlen(config.logo[2]) + config.spacing : 0);
482 |
483 | printed[0] = 0;
484 |
485 | if(print_logo) {
486 | getLogoLine(printed, &line);
487 |
488 | for(int i = 0; i < config.spacing; ++i)
489 | strcat(printed, " ");
490 | }
491 |
492 | strcat(printed, config.color);
493 | strcat(printed, current->label);
494 |
495 | const size_t separator_len = strlen(config.separator);
496 | for(size_t i = 0; i < len && strlen(printed) < 1023 - separator_len * i; ++i)
497 | strcat(printed, config.separator);
498 | } else if(strcmp(current->id, "space") == 0) { // spacings are handled differently (they don't do shit)
499 | printed[0] = 0;
500 |
501 | if(print_logo) {
502 | getLogoLine(printed, &line);
503 |
504 | for(int i = 0; i < config.spacing; ++i)
505 | strcat(printed, " ");
506 | }
507 |
508 | strcat(printed, config.color);
509 | strcat(printed, current->label);
510 | } else if(strcmp(current->id, "title") == 0) { // titles are handled differently
511 | char name[DEST_SIZE];
512 | char host[DEST_SIZE];
513 |
514 | if(user(name) || hostname(host))
515 | continue;
516 |
517 | printed[0] = 0;
518 |
519 | if(print_logo) {
520 | getLogoLine(printed, &line);
521 |
522 | for(int i = 0; i < config.spacing; ++i)
523 | strcat(printed, " ");
524 | }
525 |
526 | strcat(printed, config.color);
527 | strcat(printed, current->label);
528 |
529 | if(_title_color)
530 | snprintf(printed + strlen(printed), 1024 - strlen(printed), "%s%s%s%s@%s%s%s", config.color, _bold ? "\033[1m" : "", name, "\033[0m", _bold ? "\033[1m" : "",
531 | config.color, host);
532 | else
533 | snprintf(printed + strlen(printed), 1024 - strlen(printed), "%s%s@%s", "\033[0m", name, host);
534 | } else if(current->func == NULL) { // printing a custom text
535 | printed[0] = 0;
536 |
537 | if(print_logo) {
538 | getLogoLine(printed, &line);
539 |
540 | for(int i = 0; i < config.spacing; ++i)
541 | strcat(printed, " ");
542 | }
543 |
544 | strcat(printed, config.color);
545 | strncat(printed, current->id, 1023 - strlen(printed));
546 | } else {
547 | int ret = current->func(data);
548 | if(ret != RET_OK) {
549 | if(ret == ERR_OOM)
550 | return ERR_OOM;
551 | continue;
552 | }
553 |
554 | char label[80];
555 | printed[0] = 0;
556 |
557 | if(print_logo) {
558 | getLogoLine(printed, &line);
559 |
560 | for(int i = 0; i < config.spacing; ++i)
561 | strcat(printed, " ");
562 | }
563 |
564 | strcat(printed, config.color);
565 | strcpy(label, current->label);
566 | if(current->label[0] && current->func != colors && current->func != lightColors)
567 | strcat(label, config.dash);
568 |
569 | snprintf(printed + strlen(printed), 1024 - strlen(printed), format, label, data);
570 | }
571 |
572 | printLine(printed, win.ws_col);
573 | }
574 |
575 | // remaining lines
576 | while(config.logo[line + 1] && print_logo) {
577 | printed[0] = 0;
578 |
579 | getLogoLine(printed, &line);
580 |
581 | printLine(printed, win.ws_col);
582 | }
583 |
584 | // memory clean up
585 | free(ascii_ptr);
586 | destroyArray(modules);
587 |
588 | return RET_OK;
589 | }
590 |
--------------------------------------------------------------------------------
/src/optdeps/glib.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "optdeps.h"
5 |
6 | #ifdef GLIB_EXISTS
7 | #include
8 | #else
9 | #include
10 | #include
11 | #include
12 | #endif // GLIB_EXISTS
13 |
14 | // use g_find_program_in_path() if glib can be used
15 | bool binaryInPath(const char *binary) {
16 | #ifdef GLIB_EXISTS
17 | // valgrind complains about this, don't really know why
18 | gchar *program = g_find_program_in_path(binary);
19 |
20 | g_free(program);
21 |
22 | if(program == NULL)
23 | return false;
24 |
25 | return true;
26 | #else
27 | char *path_env = getenv("PATH");
28 | if(path_env == NULL) {
29 | return false;
30 | }
31 |
32 | char *path = strdup(path_env);
33 | if(path == NULL) {
34 | return false;
35 | }
36 |
37 | char *dir = strtok(path, ":");
38 | while(dir) {
39 | size_t len = strlen(dir) + strlen(binary) + 2;
40 | char full_path[len];
41 | snprintf(full_path, sizeof(full_path), "%s/%s", dir, binary);
42 |
43 | if(access(full_path, X_OK) == 0) {
44 | free(path);
45 | return true;
46 | }
47 |
48 | dir = strtok(NULL, ":");
49 | }
50 |
51 | free(path);
52 | return false;
53 | #endif // GLIB_EXISTS
54 | }
55 |
--------------------------------------------------------------------------------
/src/optdeps/libpci.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "optdeps.h"
5 | #include "../config/config.h"
6 | #include "../info/info.h"
7 |
8 | #ifdef LIBPCI_EXISTS
9 | #include
10 | #else
11 | #include "../utils/utils.h"
12 | #include "../utils/wrappers.h"
13 | #endif // LIBPCI_EXISTS
14 |
15 | #define CLASS0 "VGA compatible controller"
16 | #define CLASS1 "3D controller"
17 |
18 | // use libpci directly if possible, else try with lspci
19 | void getGpus(char **gpus) {
20 | #ifdef LIBPCI_EXISTS
21 | // based on https://github.com/pciutils/pciutils/blob/master/example.c
22 | char device_class[DEST_SIZE];
23 | static char namebuf[DEST_SIZE * 3];
24 | struct pci_dev *dev;
25 | struct pci_access *pacc = pci_alloc(); // get the pci_access structure;
26 | pci_init(pacc); // initialize the PCI library
27 | pci_scan_bus(pacc); // we want to get the list of devices
28 | ptrdiff_t i = 0;
29 |
30 | for(dev = pacc->devices; dev; dev = dev->next) { // iterates over all devices
31 | pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); // fill in header info
32 | pci_lookup_name(pacc, device_class, DEST_SIZE, PCI_LOOKUP_CLASS, dev->device_class);
33 | if(strcmp(device_class, CLASS0) == 0 || strcmp(device_class, CLASS1) == 0) {
34 | // look up the full name of the device
35 | if(config.gpu_index == 0) {
36 | gpus[i] = pci_lookup_name(pacc, namebuf + (i * DEST_SIZE), DEST_SIZE, PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
37 |
38 | if(i < 2)
39 | ++i;
40 | else
41 | break;
42 | } else {
43 | if(i == config.gpu_index - 1) {
44 | gpus[0] = pci_lookup_name(pacc, namebuf, DEST_SIZE, PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
45 | break;
46 | }
47 | if(i < 2)
48 | ++i;
49 | else
50 | break;
51 | }
52 | }
53 | }
54 |
55 | pci_cleanup(pacc); // close everything
56 | #else
57 | char *temp_gpus[] = {NULL, NULL, NULL};
58 |
59 | char *lspci = malloc(0x2000);
60 | if(lspci == NULL)
61 | return;
62 | char *args[] = {"lspci", "-mm", NULL};
63 | execCmd(lspci, 0x2000, args);
64 | char *current = lspci;
65 | char *ptr;
66 |
67 | for(int i = 0; i < 3; ++i) {
68 | ptr = strstr(current, CLASS0);
69 | if(ptr == NULL) {
70 | ptr = strstr(current, CLASS1);
71 | if(ptr == NULL) {
72 | break;
73 | }
74 | }
75 | char *current = ptr;
76 |
77 | for(int j = 0; j < 4; ++j) {
78 | current = strchr(current, '"');
79 | if(current == NULL)
80 | break;
81 | ++current;
82 |
83 | /* class" "manufacturer" "name"
84 | * "manufacturer" "name"
85 | * manufacturer" "name"
86 | * "name"
87 | * name"
88 | */
89 | }
90 |
91 | ptr = strchr(current, '"'); // name
92 | if(ptr == NULL)
93 | break;
94 | *ptr = 0;
95 |
96 | temp_gpus[i] = current;
97 | current = ptr + 1;
98 | }
99 |
100 | if(config.gpu_index == 0) {
101 | static char gpus_buf[768];
102 | for(ptrdiff_t i = 0; i < 3 && temp_gpus[i] != NULL; ++i) {
103 | safeStrncpy(gpus_buf + (i * DEST_SIZE), temp_gpus[0], DEST_SIZE);
104 |
105 | gpus[0] = gpus_buf + (i * DEST_SIZE);
106 | }
107 | } else if(temp_gpus[config.gpu_index - 1] != NULL) {
108 | static char gpu_buf[DEST_SIZE];
109 | safeStrncpy(gpu_buf, temp_gpus[config.gpu_index - 1], DEST_SIZE);
110 |
111 | gpus[0] = gpu_buf;
112 | }
113 |
114 | free(lspci);
115 | #endif // LIBPCI_EXISTS
116 | }
117 |
--------------------------------------------------------------------------------
/src/optdeps/optdeps.h:
--------------------------------------------------------------------------------
1 | /*
2 | * This whole idea might be really stupid.
3 | * It provides custom implementations of functions if
4 | * the related library (that I would prefer using) is
5 | * not found at compile time. It probably makes no sense
6 | * to do this (as I could probably just always use my own
7 | * implementation), but who cares
8 | */
9 |
10 | #pragma once
11 |
12 | #include
13 |
14 | // can use libc or alternatives
15 | bool binaryInPath(const char *str);
16 |
17 | void getGpus(char **gpus);
18 |
--------------------------------------------------------------------------------
/src/utils/logos.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | // A lot of these logos come from the following projects:
6 | // - neofetch: https://github.com/dylanaraps/neofetch
7 | // - fastfetch: https://github.com/fastfetch-cli/fastfetch
8 |
9 | static char *logos[][32] = {
10 | // please leave logos[0] to Linux and logos[1] to macOS
11 | {
12 | // Linux - default logo
13 | "linux", // this first line contains the distro ID, taken from /etc/os-release
14 | "\033[90m", // default color for the printed text
15 | " ##### ", // just the logo
16 | " ####### ", " ##\033[37mO\033[90m#\033[37mO\033[90m## ", " #\033[33m#####\033[90m# ",
17 | " ##\033[37m##\033[33m###\033[37m##\033[90m## ", " #\033[37m##########\033[90m## ", " #\033[37m############\033[90m## ",
18 | " #\033[37m############\033[90m### ", " ##\033[90m#\033[37m###########\033[90m##\033[33m# ", "######\033[90m#\033[37m#######\033[90m#\033[33m######",
19 | "#######\033[90m#\033[37m#####\033[90m#\033[33m#######", " #####\033[90m#######\033[33m##### ",
20 | NULL // the logo is terminated by NULL
21 | },
22 | {// macOS
23 | "apple",
24 | "\033[35m",
25 | "\033[32m 'c. ",
26 | "\033[32m ,xNMM. ",
27 | "\033[32m .OMMMMo ",
28 | "\033[32m OMMM0, ",
29 | "\033[32m .;loddo:' loolloddol;. ",
30 | "\033[32m cKMMMMMMMMMMNWMMMMMMMMMM0: ",
31 | "\033[33m .KMMMMMMMMMMMMMMMMMMMMMMMWd. ",
32 | "\033[33m XMMMMMMMMMMMMMMMMMMMMMMMX. ",
33 | "\033[31m;MMMMMMMMMMMMMMMMMMMMMMMM: ",
34 | "\033[31m:MMMMMMMMMMMMMMMMMMMMMMMM: ",
35 | "\033[31m.MMMMMMMMMMMMMMMMMMMMMMMMX. ",
36 | "\033[31m kMMMMMMMMMMMMMMMMMMMMMMMMWd. ",
37 | " .XMMMMMMMMMMMMMMMMMMMMMMMMMMk",
38 | " .XMMMMMMMMMMMMMMMMMMMMMMMMK.",
39 | "\033[34m kMMMMMMMMMMMMMMMMMMMMMMd ",
40 | "\033[34m ;KMMMMMMMWXXWMMMMMMMk. ",
41 | "\033[34m .cooc,. .,coo:. ",
42 | NULL},
43 | {// Android
44 | "android",
45 | "\033[32m",
46 | " -o o- ",
47 | " +hydNNNNdyh+ ",
48 | " +mMMMMMMMMMMMMm+ ",
49 | " `dMM\033[37mm:\033[32mNMMMMMMN\033[37m:m\033[32mMMd` ",
50 | " hMMMMMMMMMMMMMMMMMMh ",
51 | " .. yyyyyyyyyyyyyyyyyyyy .. ",
52 | ".mMMm`MMMMMMMMMMMMMMMMMMMM`mMMm.",
53 | ":MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM:",
54 | ":MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM:",
55 | ":MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM:",
56 | ":MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM:",
57 | "-MMMM-MMMMMMMMMMMMMMMMMMMM-MMMM-",
58 | " +yy+ MMMMMMMMMMMMMMMMMMMM +yy+ ",
59 | " mMMMMMMMMMMMMMMMMMMm ",
60 | " `/++MMMMh++hMMMM++/` ",
61 | " MMMMo oMMMM ",
62 | " MMMMo oMMMM ",
63 | " oNMm- -mMNs ",
64 | NULL},
65 | {// Arch Linux
66 | "arch",
67 | "\033[36m",
68 | " -` ",
69 | " .o+` ",
70 | " `ooo/ ",
71 | " `+oooo: ",
72 | " `+oooooo: ",
73 | " -+oooooo+: ",
74 | " `/:-:++oooo+: ",
75 | " `/++++/+++++++: ",
76 | " `/++++++++++++++: ",
77 | " `/+++ooooooooooooo/` ",
78 | " ./ooosssso++osssssso+` ",
79 | " .oossssso-````/ossssss+` ",
80 | " -osssssso. :ssssssso. ",
81 | " :osssssss/ osssso+++. ",
82 | " /ossssssss/ +ssssooo/- ",
83 | " `/ossssso+/:- -:/+osssso+- ",
84 | " `+sso+:-` `.-/+oso: ",
85 | "`++:. `-/+/",
86 | ".` `/",
87 | NULL},
88 | {// Arch Linux (small version)
89 | "arch_small", "\033[36m", " /\\ ", " / \\ ", " /\\ \\ ", " / \\ ", " / ,, \\ ", " / | | -\\ ", "/_-'' ''-_\\", NULL},
90 | {// Debian
91 | "debian",
92 | "\033[31m",
93 | " _,met$$$$$gg. ",
94 | " ,g$$$$$$$$$$$$$$$P. ",
95 | " ,g$$P\" \"\"\"Y$$.\". ",
96 | " ,$$P' `$$$. ",
97 | "',$$P ,ggs. `$$b: ",
98 | "`d$$' ,$P\"' \033[37m.\033[31m $$$ ",
99 | " $$P d$' \033[37m,\033[31m $$P ",
100 | " $$: $$. \033[37m-\033[31m ,d$$' ",
101 | " $$; Y$b._ _,d$P' ",
102 | " Y$$. \033[37m`.\033[31m`\"Y$$$$P\"' ",
103 | " `$$b \033[37m\"-.__\033[31m ",
104 | " `Y$$ ",
105 | " `Y$$. ",
106 | " `$$b. ",
107 | " `Y$$b. ",
108 | " `\"Y$b._ ",
109 | " `\"\"\" ",
110 | NULL},
111 | {// Linux Mint
112 | "linuxmint",
113 | "\033[32m",
114 | "\033[37m ...-:::::-... ",
115 | "\033[37m .-MMMMMMMMMMMMMMM-. ",
116 | "\033[37m .-MMMM\033[32m`..-:::::::-..`\033[37mMMMM-. ",
117 | "\033[37m .:MMMM\033[32m.:MMMMMMMMMMMMMMM:.\033[37mMMMM:. ",
118 | "\033[37m -MMM\033[32m-M---MMMMMMMMMMMMMMMMMMM.\033[37mMMM- ",
119 | "\033[37m `:MMM\033[32m:MM` :MMMM:....::-...-MMMM:\033[37mMMM:` ",
120 | "\033[37m :MMM\033[32m:MMM` :MM:` `` `` `:MMM:\033[37mMMM: ",
121 | "\033[37m.MMM\033[32m.MMMM` :MM. -MM. .MM- `MMMM.\033[37mMMM.",
122 | "\033[37m:MMM\033[32m:MMMM` :MM. -MM- .MM: `MMMM-\033[37mMMM:",
123 | "\033[37m:MMM\033[32m:MMMM` :MM. -MM- .MM: `MMMM:\033[37mMMM:",
124 | "\033[37m:MMM\033[32m:MMMM` :MM. -MM- .MM: `MMMM-\033[37mMMM:",
125 | "\033[37m.MMM\033[32m.MMMM` :MM:--:MM:--:MM: `MMMM.\033[37mMMM.",
126 | "\033[37m :MMM\033[32m:MMM- `-MMMMMMMMMMMM-` -MMM-\033[37mMMM: ",
127 | "\033[37m :MMM\033[32m:MMM:` `:MMM:\033[37mMMM: ",
128 | "\033[37m .MMM\033[32m.MMMM:--------------:MMMM.\033[37mMMM. ",
129 | "\033[37m '-MMMM\033[32m.-MMMMMMMMMMMMMMM-.\033[37mMMMM-' ",
130 | "\033[37m '.-MMMM\033[32m``--:::::--``\033[37mMMMM-.' ",
131 | "\033[37m '-MMMMMMMMMMMMM-' ",
132 | "\033[37m ``-:::::-`` ",
133 | NULL},
134 | {// Endeavour OS
135 | "endeavouros", "\033[35m", "\033[31m ./\033[35mo\033[34m. ", "\033[31m ./\033[35msssso\033[34m- ",
136 | "\033[31m `:\033[35mosssssss+\033[34m- ", "\033[31m `:+\033[35msssssssssso\033[34m/. ",
137 | "\033[31m `-/o\033[35mssssssssssssso\033[34m/. ", "\033[31m `-/+\033[35msssssssssssssssso\033[34m+:` ",
138 | "\033[31m `-:/+\033[35msssssssssssssssssso«\033[34m+/. ", "\033[31m `.://\033[35mosssssssssssssssssssso\033[34m++- ",
139 | "\033[31m .://+\033[35mssssssssssssssssssssssso\033[34m++: ", "\033[31m .:///\033[35mossssssssssssssssssssssssso\033[34m++: ",
140 | "\033[31m `:////\033[35mssssssssssssssssssssssssssso\033[34m+++.", "\033[31m`-////+\033[35mssssssssssssssssssssssssssso\033[34m++++-",
141 | "\033[31m `..-+\033[35moosssssssssssssssssssssssso\033[34m+++++/`", "\033[34m ./++++++++++++++++++++++++++++++/:. ", "\033[34m `:::::::::::::::::::::::::------`` ",
142 | NULL},
143 | {// Ubuntu
144 | "ubuntu",
145 | "\033[31m",
146 | " .-/+oossssoo+/-. ",
147 | " `:+ssssssssssssssssss+:` ",
148 | " -+ssssssssssssssssssyyssss+- ",
149 | " .ossssssssssssssssss\033[37mdMMMNy\033[31msssso. ",
150 | " /sssssssssss\033[37mhdmmNNmmyNMMMMh\033[31mssssss/ ",
151 | " +sssssssss\033[37mhm\033[31myd\033[37mMMMMMMMNddddy\033[31mssssssss+ ",
152 | " /ssssssss\033[37mhNMMM\033[31myh\033[37mhyyyyhmNMMMNh\033[31mssssssss/ ",
153 | ".ssssssss\033[37mdMMMNh\033[31mssssssssss\033[37mhNMMMd\033[31mssssssss.",
154 | "+ssss\033[37mhhhyNMMNy\033[31mssssssssssss\033[37myNMMMy\033[31msssssss+",
155 | "oss\033[37myNMMMNyMMh\033[31mssssssssssssss\033[37mhmmmh\033[31mssssssso",
156 | "oss\033[37myNMMMNyMMh\033[31msssssssssssssshmmmhssssssso",
157 | "+ssss\033[37mhhhyNMMNy\033[31mssssssssssss\033[37myNMMMy\033[31msssssss+",
158 | ".ssssssss\033[37mdMMMNh\033[31mssssssssss\033[37mhNMMMd\033[31mssssssss.",
159 | " /ssssssss\033[37mhNMMM\033[31myh\033[37mhyyyyhdNMMMNh\033[31mssssssss/ ",
160 | " +sssssssss\033[37mdm\033[31myd\033[37mMMMMMMMMddddy\033[31mssssssss+ ",
161 | " /sssssssssss\033[37mhdmNNNNmyNMMMMh\033[31mssssss/ ",
162 | " .ossssssssssssssssss\033[37mdMMMNy\033[31msssso. ",
163 | " -+sssssssssssssssss\033[37myyy\033[31mssss+- ",
164 | " `:+ssssssssssssssssss+:` ",
165 | " .-/+oossssoo+/-. ",
166 | NULL},
167 | {// Parrot OS
168 | "parrot",
169 | "\033[36m",
170 | " `:oho/-` ",
171 | "`mMMMMMMMMMMMNmmdhy- ",
172 | " dMMMMMMMMMMMMMMMMMMs` ",
173 | " +MMsohNMMMMMMMMMMMMMm/ ",
174 | " .My .+dMMMMMMMMMMMMMh. ",
175 | " + :NMMMMMMMMMMMMNo ",
176 | " `yMMMMMMMMMMMMMm: ",
177 | " /NMMMMMMMMMMMMMy` ",
178 | " .hMMMMMMMMMMMMMN+ ",
179 | " ``-NMMMMMMMMMd- ",
180 | " /MMMMMMMMMMMs` ",
181 | " mMMMMMMMsyNMN/ ",
182 | " +MMMMMMMo :sNh. ",
183 | " `NMMMMMMm -o/",
184 | " oMMMMMMM. ",
185 | " `NMMMMMM+ ",
186 | " +MMd/NMh ",
187 | " mMm -mN` ",
188 | " /MM `h: ",
189 | " dM` . ",
190 | " :M- ",
191 | " d: ",
192 | " -+ ",
193 | " - ",
194 | NULL},
195 | {// Mageia
196 | "mageia",
197 | "\033[36m",
198 | " .°°. ",
199 | " °° .°°. ",
200 | " .°°°. °° ",
201 | " . . ",
202 | " °°° .°°°. ",
203 | " .°°°. '___' ",
204 | " .'___' . ",
205 | "\033[37m :dkxc;'. ..,cxkd; ",
206 | "\033[37m .dkk. kkkkkkkkkk .kkd. ",
207 | "\033[37m.dkk. ';cloolc;. .kkd ",
208 | "\033[37mckk. .kk;",
209 | "\033[37mxO: cOd",
210 | "\033[37mxO: lOd",
211 | "\033[37mlOO. .OO:",
212 | "\033[37m.k00. .00x ",
213 | "\033[37m .k00; ;00O. ",
214 | "\033[37m .lO0Kc;,,,,,,;c0KOc. ",
215 | "\033[37m ;d00KKKKKK00d; ",
216 | "\033[37m .,KKKK,. ",
217 | NULL},
218 | {// Manjaro Linux
219 | "manjaro", "\033[32m", "██████████████████ ████████", "██████████████████ ████████", "██████████████████ ████████", "██████████████████ ████████",
220 | "████████ ████████", "████████ ████████ ████████", "████████ ████████ ████████", "████████ ████████ ████████", "████████ ████████ ████████",
221 | "████████ ████████ ████████", "████████ ████████ ████████", "████████ ████████ ████████", "████████ ████████ ████████", "████████ ████████ ████████", NULL},
222 | {// Fedora
223 | "fedora",
224 | "\033[34m",
225 | " /:-------------:\\ ",
226 | " :-------------------:: ",
227 | " :-----------\033[39m/shhOHbmp\033[34m---:\\ ",
228 | " /-----------\033[39momMMMNNNMMD\033[34m] ---: ",
229 | " :-----------\033[39msMMMMNMNMP\033[34m. ---: ",
230 | " :-----------\033[39m:MMMdP\033[34m------- ---\\",
231 | ",------------\033[39m:MMMd\033[34m-------- ---:",
232 | ":------------\033[39m:MMMd\033[34m------- .---:",
233 | ":---- \033[39moNMMMMMMMMMNho\033[34m .----:",
234 | ":-- .\033[39m+shhhMMMmhhy++\033[34m .------/",
235 | ":- -------\033[39m:MMMd\033[34m--------------: ",
236 | ":- --------\033[39m/MMMd\033[34m-------------; ",
237 | ":- ------\033[39m/hMMMy\033[34m------------: ",
238 | ":-- \033[39m:dMNdhhdNMMNo\033[34m------------; ",
239 | ":---\033[39m:sdNMMMMNds:\033[34m------------: ",
240 | ":------\033[39m:://:\033[34m-------------:: ",
241 | ":---------------------:// ",
242 | NULL},
243 | {// Rocky Linux
244 | "rocky",
245 | "\033[32m",
246 | " __wgliliiligw_, ",
247 | " _williiiiiiliilililw, ",
248 | " _%iiiiiilililiiiiiiiiiii_ ",
249 | " .Qliiiililiiiiiiililililiilm. ",
250 | " _iiiiiliiiiiililiiiiiiiiiiliil, ",
251 | " .lililiiilililiiiilililililiiiii, ",
252 | "_liiiiiiliiiiiiiliiiiiF{iiiiiilili,",
253 | "jliililiiilililiiili@` ~ililiiiiiL",
254 | "iiiliiiiliiiiiiili>` ~liililii",
255 | "liliiiliiilililii` -9liiiil",
256 | "iiiiiliiliiiiii~ \"4lili",
257 | "4ililiiiiilil~| -w, )4lf",
258 | "-liiiiililiF' _liig, )'",
259 | " )iiiliii@` _QIililig, ",
260 | " )iiii>` .Qliliiiililw ",
261 | " )<>~ .mliiiiiliiiiiil, ",
262 | " _gllilililiililii~ ",
263 | " giliiiiiiiiiiiiT` ",
264 | " -^~$ililili@~~' ",
265 | NULL},
266 | {// KDE Neon
267 | "neon",
268 | "\033[32m",
269 | " `..---+/---..` ",
270 | " `---.`` `` `.---.` ",
271 | " .--.` `` `-:-. ",
272 | " `:/: `.----//----.` :/- ",
273 | " .:. `---` `--.` .:` ",
274 | " .:` `--` .:- `:. ",
275 | " `/ `:. `.-::-.` -:` `/` ",
276 | " /. /. `:++++++++:` .: .: ",
277 | "`/ .: `+++++++++++/ /` `+`",
278 | "/+` -- .++++++++++++` :. .+:",
279 | "`/ .: `+++++++++++/ /` `+`",
280 | " /` /. `:++++++++:` .: .: ",
281 | " ./ `:. `.:::-.` -:` `/` ",
282 | " .:` `--` .:- `:. ",
283 | " .:. `---` `--.` .:` ",
284 | " `:/: `.----//----.` :/- ",
285 | " .-:.` `` `-:-. ",
286 | " `---.`` `` `.---.` ",
287 | " `..---+/---..` ",
288 | NULL},
289 | {// NixOS
290 | "nixos",
291 | "\033[36m",
292 | "\033[34m ::::. \033[36m '::::: ::::' ",
293 | "\033[34m '::::: \033[36m':::::. ::::' ",
294 | "\033[34m ::::: \033[36m'::::.::::: ",
295 | "\033[34m .......:::::..... \033[36m:::::::: ",
296 | "\033[34m ::::::::::::::::::. \033[36m:::::: \033[34m::::. ",
297 | "\033[34m ::::::::::::::::::::: \033[36m:::::. \033[34m.::::' ",
298 | " ..... \033[36m::::' \033[34m:::::' ",
299 | " ::::: \033[36m'::' \033[34m:::::' ",
300 | " ........::::: \033[36m' \033[34m:::::::::::.",
301 | "::::::::::::: \033[34m:::::::::::::",
302 | " ::::::::::: \033[34m.. \033[34m::::: ",
303 | " .::::: \033[34m.::: \033[34m::::: ",
304 | " .::::: \033[34m::::: \033[34m''''' \033[36m..... ",
305 | " ::::: \033[34m':::::. \033[36m......:::::::::::::' ",
306 | " ::: \033[34m::::::. \033[36m':::::::::::::::::' ",
307 | "\033[34m .:::::::: \033[36m':::::::::: ",
308 | "\033[34m .::::''::::. \033[36m'::::. ",
309 | "\033[34m .::::' ::::. \033[36m'::::. ",
310 | "\033[34m .:::: :::: \033[36m'::::. ",
311 | NULL},
312 | {// Pop!_OS
313 | "pop",
314 | "\033[36m",
315 | " ///////////// ",
316 | " ///////////////////// ",
317 | " ///////\033[39m*767\033[36m//////////////// ",
318 | " //////\033[39m7676767676*\033[36m////////////// ",
319 | " /////\033[39m76767\033[36m//\033[39m7676767\033[36m////////////// ",
320 | " /////\033[39m767676\033[36m///\033[39m*76767\033[36m/////////////// ",
321 | " ///////\033[39m767676\033[36m///\033[39m76767\033[36m].///\033[39m7676*\033[36m///////",
322 | "/////////\033[39m767676\033[36m//\033[39m76767\033[36m///\033[39m767676\033[36m////////",
323 | "//////////\033[39m76767676767\033[36m////\033[39m76767\033[36m/////////",
324 | "///////////\033[39m76767676\033[36m//////\033[39m7676\033[36m//////////",
325 | "////////////,\033[39m7676\033[36m,///////\033[39m767\033[36m///////////",
326 | "/////////////*\033[39m7676\033[36m///////\033[39m76\033[36m////////////",
327 | "///////////////\033[39m7676\033[36m////////////////////",
328 | " ///////////////\033[39m7676\033[36m///\033[39m767\033[36m//////////// ",
329 | " //////////////////////\033[39m'\033[36m//////////// ",
330 | " //////\033[39m.7676767676767676767,\033[36m////// ",
331 | " /////\033[39m767676767676767676767\033[36m///// ",
332 | " /////////////////////////// ",
333 | " ///////////////////// ",
334 | " ///////////// ",
335 | NULL},
336 | {// Gentoo
337 | "gentoo",
338 | "\033[35m",
339 | " -/oyddmdhs+:. ",
340 | " -o\033[97mdNMMMMMMMMNNmhy+\033[35m-` ",
341 | " -y\033[97mNMMMMMMMMMMMNNNmmdhy\033[35m+- ",
342 | " `o\033[97mmMMMMMMMMMMMMNmdmmmmddhhy\033[35m/` ",
343 | " om\033[97mMMMMMMMMMMMN\033[35mhhyyyo\033[97mhmdddhhhd\033[35mo` ",
344 | ".y\033[97mdMMMMMMMMMMd\033[35mhs++so/s\033[97mmdddhhhhdm\033[35m+` ",
345 | " oy\033[97mhdmNMMMMMMMN\033[35mdyooy\033[97mdmddddhhhhyhN\033[35md.",
346 | " :o\033[97myhhdNNMMMMMMMNNNmmdddhhhhhyym\033[35mMh",
347 | " .:\033[97m+sydNMMMMMNNNmmmdddhhhhhhmM\033[35mmy",
348 | " /m\033[97mMMMMMMNNNmmmdddhhhhhmMNh\033[35ms:",
349 | " `o\033[97mNMMMMMMMNNNmmmddddhhdmMNhs\033[35m+` ",
350 | " `s\033[97mNMMMMMMMMNNNmmmdddddmNMmhs\033[35m/. ",
351 | " /N\033[97mMMMMMMMMNNNNmmmdddmNMNdso\033[35m:` ",
352 | "+M\033[97mMMMMMMNNNNNmmmmdmNMNdso\033[35m/- ",
353 | "yM\033[97mMNNNNNNNmmmmmNNMmhs+/\033[35m-` ",
354 | "/h\033[97mMMNNNNNNNNMNdhs++/\033[35m-` ",
355 | " `/\033[97mohdmmddhys+++/:\033[35m.` ",
356 | " `-//////:--. ",
357 | NULL},
358 | {// Windows
359 | "windows", "\033[34m", "\033[31m ,.=:!!t3Z3z., ", "\033[31m :tt:::tt333EE3 ",
360 | "\033[31m Et:::ztt33EEEL \033[32m@Ee., .., ", "\033[31m ;tt:::tt333EE7 \033[32m;EEEEEEttttt33# ", "\033[31m :Et:::zt333EEQ. \033[32m$EEEEEttttt33QL ",
361 | "\033[31m it::::tt333EEF \033[32m@EEEEEEttttt33F ", "\033[31m ;3=*^```\"*4EEV \033[32m:EEEEEEttttt33@. ", " ,.=::::!t=., \033[31m` \033[32m@EEEEEEtttz33QF ",
362 | " ;::::::::zt33) \033[32m\"4EEEtttji3P* ", " :t::::::::tt33.\033[33m:Z3z.. \033[32m`` \033[33m,..g. ", " i::::::::zt33F \033[33mAEEEtttt::::ztF ",
363 | " ;:::::::::t33V \033[33m;EEEttttt::::t3 ", " E::::::::zt33L \033[33m@EEEtttt::::z3F ", "{3=*^```\"*4E3) \033[33m;EEEtttt:::::tZ` ",
364 | " `\033[33m \033[33m:EEEEtttt::::z7 ", "\033[33m \"VEzjt:;;z>*` ", NULL},
365 | {// ElementaryOS
366 | "elementary",
367 | "\033[34m",
368 | "\033[90m eeeeeeeeeeeeeeeee ",
369 | "\033[97m eeeeeeeeeeeeeeeeeeeeeee ",
370 | "\033[97m eeeee eeeeeeeeeeee eeeee ",
371 | "\033[97m eeee eeeee eee eeee ",
372 | "\033[97m eeee eeee eee eeee ",
373 | "\033[97meee eee eee eee ",
374 | "\033[97meee eee eee eee ",
375 | "\033[97mee eee eeee eeee ",
376 | "\033[97mee eee eeeee eeeeee ",
377 | "\033[97mee eee eeeee eeeee ee ",
378 | "\033[97meee eeee eeeeee eeeee eee ",
379 | "\033[97meee eeeeeeeeee eeeeee eee ",
380 | "\033[97m eeeeeeeeeeeeeeeeeeeeeeee eeeee ",
381 | "\033[97m eeeeeeee eeeeeeeeeeee eeee ",
382 | "\033[97m eeeee eeeee ",
383 | "\033[97m eeeeeee eeeeeee ",
384 | "\033[97m eeeeeeeeeeeeeeeee ",
385 | NULL},
386 | {// Garuda Linux
387 | "garuda",
388 | "\033[31m",
389 | " .%;888:8898898: ",
390 | " x;XxXB%89b8:b8%b88: ",
391 | " .8Xxd 8X:. ",
392 | " .8Xx; 8x:. ",
393 | " .tt8x .d x88; ",
394 | " .@8x8; .db: xx@; ",
395 | " ,tSXX° .bbbbbbbbbbbbbbbbbbbB8x@;",
396 | " .SXxx bBBBBBBBBBBBBBBBBBBBbSBX8;",
397 | " ,888S pd!",
398 | "8X88/ q ",
399 | "8X88/ ",
400 | "GBB. ",
401 | " x%88 d888@8@X@X@X88X@@XX@@X@8@X. ",
402 | " dxXd dB8b8b8B8B08bB88b998888b88x. ",
403 | " dxx8o .@@;. ",
404 | " dx88 .t@x. ",
405 | " d:SS@8ba89aa67a853Sxxad. ",
406 | " .d988999889889899dd. ",
407 | NULL},
408 | {// Alpine Linux
409 | "alpine",
410 | "\033[34m",
411 | " .hddddddddddddddddddddddh. ",
412 | " :dddddddddddddddddddddddddd: ",
413 | " /dddddddddddddddddddddddddddd/ ",
414 | " +dddddddddddddddddddddddddddddd+ ",
415 | " `sdddddddddddddddddddddddddddddddds` ",
416 | " `ydddddddddddd++hdddddddddddddddddddy` ",
417 | " `ydddddddddddd++hdddddddddddddddddddy` ",
418 | "hdddddddddd+` `+y: .sddddddddddh",
419 | "ddddddddh+` `//` `.` -sddddddddd",
420 | "ddddddh+` `/hddh/` `:s- -sddddddd",
421 | "ddddh+` `/+/dddddh/` `+s- -sddddd",
422 | "ddd+` `/o` :dddddddh/` `oy- .yddd",
423 | "hdddyo+ohddyosdddddddddho+oydddy++ohdddh",
424 | ".hddddddddddddddddddddddddddddddddddddh.",
425 | " `yddddddddddddddddddddddddddddddddddy` ",
426 | " `sdddddddddddddddddddddddddddddddds` ",
427 | " +dddddddddddddddddddddddddddddd+ ",
428 | " /dddddddddddddddddddddddddddd/ ",
429 | " :dddddddddddddddddddddddddd: ",
430 | " .hddddddddddddddddddddddh. ",
431 | NULL},
432 | {// Empty Logo
433 | "none", "", "", NULL},
434 | };
435 |
--------------------------------------------------------------------------------
/src/utils/queue.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "queue.h"
6 | #include "../utils/return.h"
7 |
8 | Queue *queueWithSIze(size_t size) {
9 | Queue *q = malloc(sizeof(Queue));
10 | if(q == NULL)
11 | return NULL;
12 |
13 | size_t byte_size = sizeof(char) * size;
14 | q->data = malloc(byte_size);
15 | if(q->data == NULL)
16 | return NULL;
17 | memset(q->data, 0, byte_size);
18 |
19 | q->alloc_size = size;
20 | q->size = 0;
21 | q->offset = 0;
22 |
23 | return q;
24 | }
25 |
26 | int requeue(Queue *q) {
27 | // If there is no available space,
28 | // requeueing won't do anything.
29 | if(q->size == q->alloc_size)
30 | return ERR_GENERIC;
31 |
32 | size_t used_byte_size = sizeof(char) * q->size;
33 | char buf[q->size];
34 |
35 | char *relevant_data_start = q->data + q->offset;
36 | memcpy(buf, relevant_data_start, used_byte_size);
37 |
38 | memcpy(q->data, buf, used_byte_size);
39 | q->offset = 0;
40 |
41 | return RET_OK;
42 | }
43 |
44 | int enqueue(Queue *q, char val) {
45 | if(q->size >= q->alloc_size)
46 | return QUEUE_FULL;
47 |
48 | size_t write_index = q->size + q->offset;
49 |
50 | if(write_index >= q->alloc_size) {
51 | // We know that a requeue is possible because we check that the queue is not full.
52 | requeue(q);
53 | write_index = q->size;
54 | }
55 |
56 | q->data[write_index] = val;
57 | q->size++;
58 |
59 | return QUEUE_OK;
60 | }
61 |
62 | int dequeue(Queue *q, char *out) {
63 | // If there is no elements in the array, returns the null character.
64 | if(q->size < 1)
65 | return QUEUE_EMPTY;
66 |
67 | // If the offset is greater than data,
68 | // it points to nothing.
69 | if(q->offset >= q->alloc_size)
70 | return QUEUE_EMPTY;
71 |
72 | char front = q->data[q->offset];
73 |
74 | q->offset++; // Increment the front.
75 | q->size--; // Decrease the size since we removed a character.
76 |
77 | *out = front;
78 |
79 | return QUEUE_OK;
80 | }
81 |
82 | void destroyQueue(Queue *q) {
83 | free(q->data);
84 | free(q);
85 | }
86 |
87 | void readAfterSequence(FILE *fp, const char *seq, char *buffer, size_t buffer_size) {
88 | size_t seq_size = strlen(seq);
89 | Queue *q = queueWithSIze(3 * seq_size);
90 | if(q == NULL)
91 | return;
92 | int ch;
93 | int error;
94 | bool found = false;
95 | char elem;
96 |
97 | while((ch = fgetc(fp)) != EOF) {
98 | if(q->size < seq_size) {
99 | enqueue(q, ch);
100 | continue;
101 | }
102 |
103 | assert(q->size == seq_size); // Window is of correct width
104 |
105 | if(strncmp(q->data + q->offset, seq, seq_size) == 0) {
106 | found = true;
107 | break;
108 | }
109 |
110 | error = dequeue(q, &elem);
111 | assert(error != QUEUE_EMPTY); // Queue should always have at least `seq_size` items
112 |
113 | error = enqueue(q, ch);
114 | assert(error != QUEUE_FULL); // Queue should maintain same size, as 1 item is added and another is removed
115 | }
116 |
117 | destroyQueue(q);
118 |
119 | if(found == false) {
120 | buffer[0] = 0; // make buffer an empty string if the sequence is not found
121 | }
122 |
123 | // Actually read for the rest of the file, or the buffer.
124 | for(size_t i = 0; i < buffer_size; ++i) {
125 | if((ch = fgetc(fp)) == EOF)
126 | break;
127 |
128 | buffer[i] = ch;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/utils/queue.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | #define QUEUE_OK 0
8 | #define QUEUE_EMPTY (-1)
9 | #define QUEUE_FULL (-2)
10 |
11 | typedef struct {
12 | size_t offset;
13 | size_t size;
14 | size_t alloc_size;
15 | char *data;
16 | } Queue;
17 |
18 | Queue *queueWithSIze(size_t size);
19 |
20 | int requeue(Queue *q);
21 |
22 | int enqueue(Queue *q, char val);
23 |
24 | int dequeue(Queue *q, char *out);
25 |
26 | void destroyQueue(Queue *q);
27 |
28 | void readAfterSequence(FILE *fp, const char *seq, char *buffer, size_t buffer_size);
29 |
--------------------------------------------------------------------------------
/src/utils/return.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define RET_OK 0x00
4 |
5 | #define ERR_USER 0x10
6 | #define ERR_GENERIC 0x11
7 |
8 | #define ERR_UNSUPPORTED 0x20
9 | #define ERR_NO_INFO 0x21
10 | #define ERR_PARSING 0x22
11 | #define ERR_NO_FILE 0x23
12 | #define ERR_OOM 0x24
13 |
--------------------------------------------------------------------------------
/src/utils/utils.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "utils.h"
7 | #include "return.h"
8 | #include "wrappers.h"
9 | #include "../config/config.h"
10 | #include "../config/parsing.h"
11 |
12 | // copy an ascii art from file to mem
13 | void *fileToLogo(char *file) {
14 | FILE *fp = fopen(file, "r");
15 | if(fp == NULL) {
16 | perror(file);
17 | return NULL;
18 | }
19 |
20 | /*
21 | * mem is assumed to be a 10 KiB buffer, aka 10240 B.
22 | * this will be filled in with up to 64 lines,
23 | * each of which can be up to 160 bytes long.
24 | * (LINE_LEN * LINE_COUNT) should equal this size.
25 | * Check out main.c, line 132
26 | */
27 | #define LINE_LEN 256
28 | #define LINE_COUNT 40
29 |
30 | // where the final logo is saved
31 | static char *logo[LINE_COUNT + 1];
32 | char *mem = NULL;
33 |
34 | char *buffer = NULL;
35 | size_t len = 0;
36 | size_t line_len;
37 | ptrdiff_t i = 0;
38 |
39 | // setting the correct color (or eventually the first line)
40 |
41 | line_len = getline(&buffer, &len, fp); // save the first line to buffer
42 | if(line_len == (size_t)-1) { // getline returns -1 in case of error
43 | free(buffer);
44 | return NULL;
45 | }
46 |
47 | if(buffer[line_len - 1] == '\n')
48 | buffer[line_len - 1] = 0;
49 |
50 | config.color[0] = 0;
51 |
52 | const char *colors[][2] = {
53 | {"black", "\033[30m"}, {"red", "\033[31m"}, {"green", "\033[32m"}, {"yellow", "\033[33m"}, {"blue", "\033[34m"},
54 | {"purple", "\033[35m"}, {"cyan", "\033[36m"}, {"gray", "\033[90m"}, {"white", "\033[37m"},
55 | };
56 |
57 | for(int j = 0; j < 9; ++j)
58 | if(strcmp(buffer, *colors[j]) == 0)
59 | strcpy(config.color, colors[j][1]);
60 |
61 | if(config.color[0] == 0) {
62 | unescape(buffer);
63 |
64 | mem = malloc(LINE_LEN);
65 | if(mem == NULL) {
66 | perror("malloc");
67 | return NULL;
68 | }
69 |
70 | safeStrncpy(mem, buffer, LINE_LEN);
71 |
72 | ++i;
73 | }
74 |
75 | // for every remaining line of the logo...
76 | while((line_len = getline(&buffer, &len, fp)) != (size_t)-1 && i < LINE_COUNT) {
77 | if(buffer[line_len - 1] == '\n')
78 | buffer[line_len - 1] = 0;
79 |
80 | unescape(buffer);
81 |
82 | void *newmem = realloc(mem, (i + 1) * LINE_LEN);
83 | if(newmem == NULL) {
84 | free(mem);
85 | perror("realloc");
86 | return NULL;
87 | }
88 | mem = newmem;
89 |
90 | safeStrncpy(mem + (i * LINE_LEN), buffer, LINE_LEN);
91 |
92 | ++i;
93 | }
94 | // cleaning up
95 | free(buffer);
96 | fclose(fp);
97 |
98 | // set up the logo metadata;
99 | logo[0] = "custom"; // logo ID
100 |
101 | for(ptrdiff_t j = 0; j < i; ++j)
102 | logo[j + 2] = mem + (j * LINE_LEN);
103 |
104 | // the array of lines is NULL-terminated;
105 | logo[i + 2] = NULL;
106 |
107 | // finally, the logo can be saved
108 | config.logo = logo;
109 |
110 | return mem;
111 | }
112 |
113 | // add a module containing id to array
114 | void addModule(struct SModule *array, char *id) {
115 | struct SModule *new = malloc(sizeof(struct SModule));
116 | if(new == NULL)
117 | return;
118 | struct SModule *last = array;
119 |
120 | for(struct SModule *current = array; current->next; current = current->next)
121 | last = current->next;
122 |
123 | last->next = new;
124 |
125 | new->id = malloc(strlen(id) + 1);
126 | if(new->id == NULL)
127 | return;
128 | strcpy(new->id, id);
129 |
130 | new->label = NULL;
131 | new->func = NULL;
132 |
133 | new->next = NULL;
134 | }
135 |
136 | // free every module in array
137 | void destroyArray(struct SModule *array) {
138 | struct SModule *current = array;
139 | struct SModule *next;
140 |
141 | while(current) {
142 | next = current->next;
143 | free(current->id);
144 | free(current);
145 | current = next;
146 | }
147 | }
148 |
149 | // print a certain line of the logo
150 | void getLogoLine(char *dest, unsigned *line) {
151 | if(config.logo == NULL || dest == NULL || *line < 1)
152 | return;
153 |
154 | if(config.logo[(*line) + 1]) {
155 | ++(*line);
156 | strcat(dest, config.logo[*line]);
157 | } else {
158 | for(size_t i = 0; i < realStrlen(config.logo[2]); ++i)
159 | strcat(dest, " ");
160 | }
161 | }
162 |
163 | // print no more than maxlen visible characters of line
164 | void printLine(char *line, const size_t maxlen) {
165 | if(_bold)
166 | fputs("\033[1m", stdout);
167 | fputs(config.color, stdout);
168 |
169 | bool escaping = false;
170 | int unicode = 0;
171 |
172 | for(size_t i = 0, len = 0; len < maxlen && i < strlen(line); ++i) {
173 | putc(line[i], stdout);
174 |
175 | if(line[i] == '\n')
176 | break;
177 | else if(line[i] == '\033')
178 | escaping = true;
179 | else if(line[i] & 0x80) { // is the 1st bit 1?
180 | if(line[i] & 0x40) { // is the 2nd bit 1?
181 | if(line[i] & 0x20) { // is the 3rd bit 1?
182 | if(line[i] & 0x10) // is the 4th bit 1?
183 | unicode = 3; // first of 4 unicode bytes (0b11110xxx)
184 | else
185 | unicode = 2; // first of 3 unicode bytes (0b1110xxxx)
186 | } else
187 | unicode = 1; // first of 2 unicode bytes (0b110xxxxx)
188 | } else if(unicode-- == 1) // unicode continuation byte (0b10xxxxxx)
189 | ++len;
190 | } else {
191 | // look mom, I just wanted to try to write some branchless code
192 |
193 | // this line is a bit weird
194 | // ++len <=> escaping == 0
195 | len += (size_t)1 - escaping;
196 |
197 | /* m is found and escaping => escaping = 0
198 | * m is found and not escaping => escaping = 0
199 | * m is not found and escaping => escaping = 1
200 | * m is not found and not escaping => escaping = 0
201 | */
202 | escaping = (line[i] != 'm') && escaping;
203 | }
204 | }
205 |
206 | fputs("\033[0m\n", stdout);
207 | }
208 |
--------------------------------------------------------------------------------
/src/utils/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | // element of a module linked list
8 | struct SModule {
9 | char *id; // module identifier
10 | char *label; // module label
11 | int (*func)(char *); // function to run
12 | struct SModule *next; // next module
13 | };
14 |
15 | void *fileToLogo(char *file);
16 |
17 | void addModule(struct SModule *array, char *id);
18 |
19 | void destroyArray(struct SModule *array);
20 |
21 | void getLogoLine(char *dest, unsigned *line);
22 |
23 | void printLine(char *line, const size_t maxlen);
24 |
25 | void unescape(char *str);
26 |
--------------------------------------------------------------------------------
/src/utils/wrappers.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include "wrappers.h"
7 | #include "return.h"
8 |
9 | // Run a command using execvp and copy the output into buf
10 | int execCmd(char *buf, size_t len, char *const *argv) {
11 | int stderr_pipes[2];
12 | int stdout_pipes[2];
13 |
14 | if(pipe(stdout_pipes) != 0 || pipe(stderr_pipes) != 0)
15 | return ERR_GENERIC;
16 |
17 | if(fork() == 0) {
18 | close(stdout_pipes[0]);
19 | close(stderr_pipes[0]);
20 | dup2(stdout_pipes[1], STDOUT_FILENO);
21 | dup2(stderr_pipes[1], STDERR_FILENO);
22 |
23 | execvp(argv[0], argv);
24 | }
25 |
26 | wait(0);
27 |
28 | close(stderr_pipes[0]);
29 | close(stderr_pipes[1]);
30 |
31 | close(stdout_pipes[1]);
32 | buf[read(stdout_pipes[0], buf, len) - 1] = 0;
33 | close(stdout_pipes[0]);
34 |
35 | return RET_OK;
36 | }
37 |
38 | // get the printed length of a string (not how big it is in memory)
39 | __attribute__((pure)) size_t realStrlen(const char *str) {
40 | if(str == NULL)
41 | return RET_OK;
42 |
43 | size_t len = 0;
44 |
45 | bool escaping = false;
46 |
47 | // determine how long the printed string is (same logic as in printLine, utils.c)
48 | while(*str) {
49 | if(*str == '\n')
50 | break;
51 |
52 | // unicode continuation byte 0x10xxxxxx
53 | if(*str & 0x80 && (*str & 0x40) == 0) {
54 | ++str;
55 | continue;
56 | }
57 |
58 | if(*str != '\033') {
59 | len += (size_t)1 - escaping;
60 |
61 | escaping = (*str != 'm') && escaping;
62 | } else
63 | escaping = true;
64 |
65 | ++str;
66 | }
67 |
68 | return len;
69 | }
70 |
71 | // Copy no more than N characters of SRC to DEST, but always guarantee null-termination
72 | void safeStrncpy(char *dest, const char *src, size_t n) {
73 | strncpy(dest, src, n - 1);
74 | dest[n - 1] = 0;
75 | }
76 |
--------------------------------------------------------------------------------
/src/utils/wrappers.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | int execCmd(char *buf, size_t len, char *const *argv);
6 |
7 | size_t realStrlen(const char *str);
8 |
9 | void safeStrncpy(char *dest, const char *src, size_t n);
10 |
--------------------------------------------------------------------------------