Merge pull request #765 from fastfetch-cli/dev

Release v2.8.10
This commit is contained in:
Carter Li 2024-03-25 14:22:43 +08:00 committed by GitHub
commit e897a98153
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 369 additions and 198 deletions

View File

@ -377,7 +377,7 @@ jobs:
with:
msystem: CLANG64
update: true
install: git mingw-w64-clang-x86_64-7zip mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-opencl-icd
install: git mingw-w64-clang-x86_64-7zip mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-vulkan-headers mingw-w64-clang-x86_64-opencl-icd
- name: print msys version
run: uname -a
@ -439,7 +439,7 @@ jobs:
with:
msystem: CLANG32
update: true
install: git mingw-w64-clang-i686-7zip mingw-w64-clang-i686-cmake mingw-w64-clang-i686-clang mingw-w64-clang-i686-vulkan-loader mingw-w64-clang-i686-opencl-icd
install: git mingw-w64-clang-i686-7zip mingw-w64-clang-i686-cmake mingw-w64-clang-i686-clang mingw-w64-clang-i686-vulkan-loader mingw-w64-clang-i686-vulkan-headers mingw-w64-clang-i686-opencl-icd
- name: print msys version
run: uname -a

12
.gitignore vendored
View File

@ -1,9 +1,9 @@
**/build/
**/.vscode/
**/.cache/
**/.kdev4/
**/.DS_Store
/.vs
build/
.vs/
.vscode/
.cache/
.kdev4/
.DS_Store
cscope.*
tags
fastfetch.kdev4

View File

@ -1,3 +1,26 @@
# 2.8.10
Changes:
* Use MS-DOS device name as mountFrom result, instead of useless GUID volume name (Windows, Disk)
* Some adjustments to Terminal detection (Terminal, Windows)
* Don't pretty print CMD
* Print conhost as Windows Console
* Don't detect `wininit` as Terminal
Bugfixes:
* Don't display 0.00 GHz (CPU, FreeBSD)
* Don't detect manufactor of Qualcomm as ARM (CPU, Android)
* Ignore `chezmoi` (Terminal, Linux)
* Trim trailing possible whitespaces (PublicIP)
* Fix detection compatibility for KDE 6 (Font, Linux)
* Always use Metal API to detect vmem size (GPU, macOS)
Features:
* Improve stability; print more useful error message; avoid misuse (PublicIP / Weather)
Logo:
* Fix color of Arco Linux
# 2.8.9
Bugfixes:

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
project(fastfetch
VERSION 2.8.9
VERSION 2.8.10
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
fastfetch (2.8.9) jammy; urgency=medium
* Update to 2.8.9
-- Carter Li <zhangsongcui@live.cn> Fri, 15 Mar 2024 10:49:42 +0800
fastfetch (2.8.8) jammy; urgency=medium
* Update to 2.8.8

2
debian/files vendored
View File

@ -1 +1 @@
fastfetch_2.8.8_source.buildinfo universe/utils optional
fastfetch_2.8.9_source.buildinfo universe/utils optional

104
presets/examples/12.jsonc Normal file
View File

@ -0,0 +1,104 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "none"
},
"display": {
"separator": "-> "
},
"modules": [
{
"type": "title",
"format": " {6}{7}{8}"
},
"break",
{
"type": "custom",
"format": "┌───────────────────────────── \u001b[1mSystem Information\u001b[0m ─────────────────────────────┐" // `\u001b` is `\033`, or `\e`
},
"break",
{
"key": "  OS ",
"keyColor": "red",
"type": "os"
},
{
"key": "  Machine ",
"keyColor": "green",
"type": "host"
},
{
"key": "  Kernel ",
"keyColor": "magenta",
"type": "kernel"
},
{
"key": " 󰅐 Uptime ",
"keyColor": "red",
"type": "uptime"
},
{
"key": " 󰍹 Resolution ",
"keyColor": "yellow",
"type": "display",
"compactType": "original-with-refresh-rate"
},
{
"key": "  WM ",
"keyColor": "blue",
"type": "wm"
},
{
"key": "  DE ",
"keyColor": "green",
"type": "de"
},
{
"key": "  Shell ",
"keyColor": "cyan",
"type": "shell"
},
{
"key": "  Terminal ",
"keyColor": "red",
"type": "terminal"
},
{
"key": "  CPU ",
"keyColor": "yellow",
"type": "cpu"
},
{
"key": " ﬙ GPU ",
"keyColor": "blue",
"type": "gpu"
},
{
"key": " 󰑭 Memory ",
"keyColor": "magenta",
"type": "memory"
},
{
"key": " 󰩟 Local IP ",
"keyColor": "red",
"type": "localip",
"compact": true
},
{
"key": " 󰩠 Public IP ",
"keyColor": "cyan",
"type": "publicip"
},
"break",
{
"type": "custom",
"format": "└──────────────────────────────────────────────────────────────────────────────┘" // `\u001b` is `\033`, or `\e`
},
"break",
{
"type": "colors",
"paddingLeft": 34,
"symbol": "circle"
}
]
}

View File

@ -2,6 +2,7 @@
#include "common/font.h"
#include <string.h>
#include <ctype.h>
void ffFontInit(FFfont* font)
{
@ -66,59 +67,33 @@ void ffFontInitQt(FFfont* font, const char* data)
//See https://doc.qt.io/qt-5/qfont.html#toString
//Family
while(*data != ',' && *data != '\0')
{
ffStrbufAppendC(&font->name, *data);
++data;
}
if(*data != '\0')
++data;
data = ffStrbufAppendSUntilC(&font->name, data, ',');
ffStrbufTrim(&font->name, ' ');
if (!data) goto exit;
data++;
//Size
while(*data != ',' && *data != '\0')
{
ffStrbufAppendC(&font->size, *data);
++data;
}
if(*data != '\0')
++data;
data = ffStrbufAppendSUntilC(&font->size, data, ',');
ffStrbufTrim(&font->size, ' ');
if (!data) goto exit;
data++;
#define FF_FONT_QT_SKIP_VALUE \
while(*data != ',' && *data != '\0') \
++data; \
if(*data != '\0') \
++data;
FF_FONT_QT_SKIP_VALUE //Pixel size
FF_FONT_QT_SKIP_VALUE //Style hint
FF_FONT_QT_SKIP_VALUE //Font weight
FF_FONT_QT_SKIP_VALUE //Font style
FF_FONT_QT_SKIP_VALUE //Underline
FF_FONT_QT_SKIP_VALUE //Strike out
FF_FONT_QT_SKIP_VALUE //Fixed pitch
FF_FONT_QT_SKIP_VALUE //Always 0
#undef FF_FONT_QT_SKIP_VALUE
while(*data != '\0')
//Style
data = strrchr(data, ',');
if (!data) goto exit;
data++;
if (isalpha(*data))
{
while(*data == ' ')
++data;
if(*data == '\0')
break;
FFstrbuf* style = ffListAdd(&font->styles);
ffStrbufInit(style);
while(*data != ' ' && *data != '\0')
do
{
ffStrbufAppendC(style, *data);
++data;
}
FFstrbuf* style = ffListAdd(&font->styles);
ffStrbufInit(style);
data = ffStrbufAppendSUntilC(style, data, ' ');
if (data) data++;
} while (data);
}
exit:
fontInitPretty(font);
}

View File

@ -20,15 +20,9 @@ typedef struct FFNetworkingState {
FFThreadType thread;
#endif
#endif
uint32_t timeout;
} FFNetworkingState;
bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers);
bool ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer, uint32_t timeout);
static inline bool ffNetworkingGetHttp(const char* host, const char* path, uint32_t timeout, const char* headers, FFstrbuf* buffer)
{
FFNetworkingState state;
if(ffNetworkingSendHttpRequest(&state, host, path, headers))
return ffNetworkingRecvHttpResponse(&state, buffer, timeout);
return false;
}
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers);
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer);

View File

@ -5,30 +5,50 @@
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h> // For FreeBSD
#include <netinet/tcp.h>
static void connectAndSend(FFNetworkingState* state)
static const char* connectAndSend(FFNetworkingState* state)
{
struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
const char* ret = NULL;
struct addrinfo* addr;
if(getaddrinfo(state->host.chars, "80", &hints, &addr) != 0)
if(getaddrinfo(state->host.chars, "80", &(struct addrinfo) {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
}, &addr) != 0)
{
ret = "getaddrinfo() failed";
goto error;
}
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if(state->sockfd == -1)
{
freeaddrinfo(addr);
ret = "socket() failed";
goto error;
}
if (state->timeout > 0)
{
FF_MAYBE_UNUSED uint32_t sec = state->timeout / 1000;
if (sec == 0) sec = 1;
#ifdef TCP_CONNECTIONTIMEOUT
setsockopt(state->sockfd, IPPROTO_TCP, TCP_CONNECTIONTIMEOUT, &sec, sizeof(sec));
#elif defined(TCP_KEEPINIT)
setsockopt(state->sockfd, IPPROTO_TCP, TCP_KEEPINIT, &sec, sizeof(sec));
#elif defined(TCP_USER_TIMEOUT)
setsockopt(state->sockfd, IPPROTO_TCP, TCP_USER_TIMEOUT, &state->timeout, sizeof(state->timeout));
#endif
}
if(connect(state->sockfd, addr->ai_addr, addr->ai_addrlen) == -1)
{
close(state->sockfd);
freeaddrinfo(addr);
ret = "connect() failed";
goto error;
}
@ -37,6 +57,7 @@ static void connectAndSend(FFNetworkingState* state)
if(send(state->sockfd, state->command.chars, state->command.length, 0) < 0)
{
close(state->sockfd);
ret = "send() failed";
goto error;
}
@ -48,11 +69,13 @@ error:
exit:
ffStrbufDestroy(&state->host);
ffStrbufDestroy(&state->command);
return ret;
}
FF_THREAD_ENTRY_DECL_WRAPPER(connectAndSend, FFNetworkingState*);
bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
ffStrbufInitS(&state->host, host);
@ -66,22 +89,30 @@ bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, con
ffStrbufAppendS(&state->command, "\r\n");
#ifdef FF_HAVE_THREADS
if (instance.config.general.multithreading)
{
state->thread = ffThreadCreate(connectAndSendThreadMain, state);
return !!state->thread;
#else
connectAndSend(state);
return state->sockfd != -1;
return state->thread ? NULL : "ffThreadCreate(connectAndSend) failed";
}
#endif
return connectAndSend(state);
}
bool ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer, uint32_t timeout)
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
{
uint32_t timeout = state->timeout;
#ifdef FF_HAVE_THREADS
if (instance.config.general.multithreading)
{
if (!ffThreadJoin(state->thread, timeout))
return false;
return "ffThreadJoin() failed or timeout";
}
#endif
if(state->sockfd == -1)
return false;
return "ffNetworkingSendHttpRequest() failed";
if(timeout > 0)
{
@ -91,14 +122,15 @@ bool ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer, ui
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev));
}
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, ffStrbufGetFree(buffer), 0);
if(received > 0)
{
uint32_t recvStart;
do {
recvStart = buffer->length;
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, ffStrbufGetFree(buffer), 0);
if (received <= 0) break;
buffer->length += (uint32_t) received;
buffer->chars[buffer->length] = '\0';
}
} while (ffStrbufGetFree(buffer) > 0 && strstr(buffer->chars + recvStart, "\r\n\r\n") == NULL);
close(state->sockfd);
return ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n");
return ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n") ? NULL : "Invalid response";
}

View File

@ -33,21 +33,20 @@ static const char* initWsaData(WSADATA* wsaData)
return NULL;
}
bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
const char* ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, const char* path, const char* headers)
{
static WSADATA wsaData;
if (wsaData.wVersion == 0)
{
if (initWsaData(&wsaData) != NULL)
const char* error = initWsaData(&wsaData);
if (error != NULL)
{
wsaData.wVersion = (WORD) -1;
return false;
return error;
}
}
else if (wsaData.wVersion == (WORD) -1)
return false;
memset(state, 0, sizeof(*state));
return "initWsaData() failed before";
struct addrinfo* addr;
@ -55,26 +54,27 @@ bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, con
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
}, &addr) != 0)
return false;
return "getaddrinfo() failed";
state->sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if(state->sockfd == INVALID_SOCKET)
{
freeaddrinfo(addr);
return false;
return "socket() failed";
}
{
//ConnectEx requires the socket to be initially bound
struct sockaddr_in addr = {
if(bind(state->sockfd, (SOCKADDR *) &(struct sockaddr_in) {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
.sin_port = 0,
};
if(bind(state->sockfd, (SOCKADDR *)&addr, sizeof(addr)) != 0)
}, sizeof(struct sockaddr_in)) != 0)
{
printf("bind %d\n", WSAGetLastError());
return false;
closesocket(state->sockfd);
freeaddrinfo(addr);
state->sockfd = INVALID_SOCKET;
return "bind() failed";
}
}
@ -93,35 +93,52 @@ bool ffNetworkingSendHttpRequest(FFNetworkingState* state, const char* host, con
if(!result && WSAGetLastError() != WSA_IO_PENDING)
{
closesocket(state->sockfd);
return false;
freeaddrinfo(addr);
state->sockfd = INVALID_SOCKET;
return "ConnectEx() failed";
}
return true;
return NULL;
}
bool ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer, uint32_t timeout)
const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buffer)
{
if (state->sockfd == INVALID_SOCKET)
return "ffNetworkingSendHttpRequest() failed";
uint32_t timeout = state->timeout;
if (timeout > 0)
{
if (WaitForSingleObject((HANDLE) state->sockfd, timeout) != WAIT_OBJECT_0)
{
CancelIo((HANDLE) state->sockfd);
closesocket(state->sockfd);
return "WaitForSingleObject(state->sockfd) failed or timeout";
}
}
DWORD transfer, flags;
if (!WSAGetOverlappedResult(state->sockfd, &state->overlapped, &transfer, TRUE, &flags))
{
closesocket(state->sockfd);
return false;
return "WSAGetOverlappedResult() failed";
}
if(timeout > 0)
{
//https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-setsockopt
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
setsockopt(state->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeout, sizeof(timeout));
}
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, (int)ffStrbufGetFree(buffer), 0);
if(received > 0)
{
buffer->length += (uint32_t) received;
uint32_t recvStart;
do {
recvStart = buffer->length;
ssize_t received = recv(state->sockfd, buffer->chars + buffer->length, (int) ffStrbufGetFree(buffer), 0);
if (received <= 0) break;
buffer->length = recvStart + (uint32_t) received;
buffer->chars[buffer->length] = '\0';
}
} while (ffStrbufGetFree(buffer) > 0 && strstr(buffer->chars + recvStart, "\r\n\r\n") == NULL);
closesocket(state->sockfd);
return ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n");
return ffStrbufStartsWithS(buffer, "HTTP/1.1 200 OK\r\n") ? NULL : "Invalid response";
}

View File

@ -11,7 +11,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
cpu->coresLogical = cpu->coresPhysical;
cpu->coresOnline = cpu->coresPhysical;
cpu->frequencyBase = ffSysctlGetInt("hw.clockrate", 0) / 1000.0;
int clockRate = ffSysctlGetInt("hw.clockrate", 0);
cpu->frequencyBase = clockRate <= 0 ? 0.0/0.0 : clockRate / 1000.0;
cpu->temperature = FF_CPU_TEMP_UNSET;
if (options->temp)

View File

@ -17,7 +17,10 @@
static void detectAndroid(FFCPUResult* cpu)
{
if (cpu->name.length == 0)
{
ffSettingsGetAndroidProperty("ro.soc.model", &cpu->name);
ffStrbufClear(&cpu->vendor); // We usually detect the vendor of CPU core as ARM, but instead we want the vendor of SOC
}
if (cpu->vendor.length == 0)
{
if (!ffSettingsGetAndroidProperty("ro.soc.manufacturer", &cpu->vendor))

View File

@ -15,7 +15,7 @@ const char* ffDetectDisksImpl(FFlist* disks)
for(uint32_t i = 0; i < length; i++)
{
const wchar_t* mountpoint = buf + i;
wchar_t* mountpoint = buf + i;
UINT driveType = GetDriveTypeW(mountpoint);
if(driveType == DRIVE_NO_ROOT_DIR)
@ -25,13 +25,6 @@ const char* ffDetectDisksImpl(FFlist* disks)
}
FFDisk* disk = ffListAdd(disks);
ffStrbufInitWS(&disk->mountpoint, mountpoint);
wchar_t volumeName[64];
if(GetVolumeNameForVolumeMountPointW(mountpoint, volumeName, sizeof(volumeName) / sizeof(*volumeName)))
ffStrbufInitWS(&disk->mountFrom, volumeName);
else
ffStrbufInit(&disk->mountFrom);
if(!GetDiskFreeSpaceExW(
mountpoint,
@ -78,6 +71,17 @@ const char* ffDetectDisksImpl(FFlist* disks)
disk->type |= FF_DISK_VOLUME_TYPE_READONLY_BIT;
}
ffStrbufInitWS(&disk->mountpoint, mountpoint);
if (mountpoint[2] == L'\\' && mountpoint[3] == L'\0')
{
wchar_t volumeName[MAX_PATH + 1];
mountpoint[2] = L'\0';
if(QueryDosDeviceW(mountpoint, volumeName, sizeof(volumeName) / sizeof(*volumeName)))
ffStrbufInitWS(&disk->mountFrom, volumeName);
else
ffStrbufInit(&disk->mountFrom);
}
//Unsupported
disk->filesUsed = 0;
disk->filesTotal = 0;

View File

@ -63,10 +63,6 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
ffStrbufInit(&gpu->driver); // Ok for both Apple and Intel
ffCfDictGetString(properties, CFSTR("CFBundleIdentifier"), &gpu->driver);
int vram; // Supported on Intel
if(!ffCfDictGetInt(properties, CFSTR("VRAM,totalMB"), &vram))
gpu->dedicated.total = (uint64_t) vram * 1024 * 1024;
if(ffCfDictGetInt(properties, CFSTR("gpu-core-count"), &gpu->coreCount)) // For Apple
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;

View File

@ -1,23 +1,35 @@
#include "publicip.h"
#include "common/networking.h"
#define FF_UNITIALIZED ((const char*)(uintptr_t) -1)
static FFNetworkingState state;
static int status = -1;
static const char* status = FF_UNITIALIZED;
void ffPreparePublicIp(FFPublicIpOptions* options)
{
if (status != -1)
if (status != FF_UNITIALIZED)
{
fputs("Error: this module can only be used once due to internal limitations\n", stderr);
exit(1);
}
state.timeout = options->timeout;
if (options->url.length == 0)
status = ffNetworkingSendHttpRequest(&state, "ipinfo.io", "/json", NULL);
else
{
FF_STRBUF_AUTO_DESTROY host = ffStrbufCreateCopy(&options->url);
ffStrbufSubstrAfterFirstS(&host, "://");
uint32_t hostStartIndex = ffStrbufFirstIndexS(&host, "://");
if (hostStartIndex < host.length)
{
if (hostStartIndex != 4 || !ffStrbufStartsWithIgnCaseS(&host, "http"))
{
fputs("Error: only http: protocol is supported. Use `Command` module with `curl` if needed\n", stderr);
exit(1);
}
ffStrbufSubstrAfter(&host, hostStartIndex + (strlen("://") - 1));
}
uint32_t pathStartIndex = ffStrbufFirstIndexC(&host, '/');
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
@ -41,18 +53,21 @@ static inline void wrapYyjsonFree(yyjson_doc** doc)
const char* ffDetectPublicIp(FFPublicIpOptions* options, FFPublicIpResult* result)
{
if (status == -1)
if (status == FF_UNITIALIZED)
ffPreparePublicIp(options);
if (status == 0)
return "Failed to connect to an IP detection server";
if (status != NULL)
return status;
FF_STRBUF_AUTO_DESTROY response = ffStrbufCreateA(4096);
bool success = ffNetworkingRecvHttpResponse(&state, &response, options->timeout);
if (success) ffStrbufSubstrAfterFirstS(&response, "\r\n\r\n");
const char* error = ffNetworkingRecvHttpResponse(&state, &response);
if (error == NULL)
ffStrbufSubstrAfterFirstS(&response, "\r\n\r\n");
else
return error;
if (!success || response.length == 0)
return "Failed to receive the server response";
if (response.length == 0)
return "Empty server response received";
if (options->url.length == 0)
{
@ -69,5 +84,6 @@ const char* ffDetectPublicIp(FFPublicIpOptions* options, FFPublicIpResult* resul
ffStrbufDestroy(&result->ip);
ffStrbufInitMove(&result->ip, &response);
ffStrbufTrimRightSpace(&result->ip);
return NULL;
}

View File

@ -280,6 +280,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
ffStrEquals(name, "xonsh") || // works in Linux but not in macOS because kernel returns `Python` in this case
ffStrEquals(name, "login") ||
ffStrEquals(name, "sshd") ||
ffStrEquals(name, "chezmoi") || // #762
#ifdef __linux__
ffStrStartsWith(name, "flatpak-") || // #707
#endif

View File

@ -143,7 +143,7 @@ static void setShellInfoDetails(FFShellResult* result)
ffStrbufSetS(&result->prettyName, "Windows PowerShell ISE");
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "cmd"))
{
ffStrbufClear(&result->prettyName);
ffStrbufSetS(&result->prettyName, "CMD");
FF_AUTO_CLOSE_FD HANDLE snapshot = NULL;
while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, result->pid)) && GetLastError() == ERROR_BAD_LENGTH) {}
@ -156,15 +156,13 @@ static void setShellInfoDetails(FFShellResult* result)
{
if(wcsncmp(module.szModule, L"clink_dll_", strlen("clink_dll_")) == 0)
{
ffStrbufAppendS(&result->prettyName, "CMD (with Clink ");
ffStrbufAppendS(&result->prettyName, " (with Clink ");
getProductVersion(module.szExePath, &result->prettyName);
ffStrbufAppendC(&result->prettyName, ')');
break;
}
}
}
if(result->prettyName.length == 0)
ffStrbufAppendS(&result->prettyName, "Command Prompt");
}
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "nu"))
ffStrbufSetS(&result->prettyName, "nushell");
@ -313,7 +311,8 @@ static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid)
ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4);
if(ffStrbufIgnCaseEqualS(&result->prettyName, "sihost") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")
ffStrbufIgnCaseEqualS(&result->prettyName, "explorer") ||
ffStrbufIgnCaseEqualS(&result->prettyName, "wininit")
) {
// A CUI program created by Windows Explorer will spawn a conhost as its child.
// However the conhost process is just a placeholder;
@ -344,7 +343,7 @@ static void setTerminalInfoDetails(FFTerminalResult* result)
: "Windows Terminal"
);
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "conhost"))
ffStrbufSetStatic(&result->prettyName, "Console Window Host");
ffStrbufSetStatic(&result->prettyName, "Windows Console");
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "Code"))
ffStrbufSetStatic(&result->prettyName, "Visual Studio Code");
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer"))

View File

@ -1,16 +1,19 @@
#include "weather.h"
#define FF_UNITIALIZED ((const char*)(uintptr_t) -1)
static FFNetworkingState state;
static int status = -1;
static const char* status = FF_UNITIALIZED;
void ffPrepareWeather(FFWeatherOptions* options)
{
if (status != -1)
if (status != FF_UNITIALIZED)
{
fputs("Error: this module can only be used once due to internal limitations\n", stderr);
exit(1);
}
state.timeout = options->timeout;
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/");
if (options->location.length)
ffStrbufAppend(&path, &options->location);
@ -21,18 +24,24 @@ void ffPrepareWeather(FFWeatherOptions* options)
const char* ffDetectWeather(FFWeatherOptions* options, FFstrbuf* result)
{
if(status == -1)
if(status == FF_UNITIALIZED)
ffPrepareWeather(options);
if(status == 0)
return "Failed to connect to 'wttr.in'";
if(status != NULL)
return status;
ffStrbufEnsureFree(result, 4095);
bool success = ffNetworkingRecvHttpResponse(&state, result, options->timeout);
if (success) ffStrbufSubstrAfterFirstS(result, "\r\n\r\n");
const char* error = ffNetworkingRecvHttpResponse(&state, result);
if (error == NULL)
{
ffStrbufSubstrAfterFirstS(result, "\r\n\r\n");
ffStrbufTrimRightSpace(result);
}
else
return error;
if(!success || result->length == 0)
return "Failed to receive the server response";
if(result->length == 0)
return "Empty server response received";
return NULL;
}

View File

@ -1,4 +1,4 @@
${c1} A
A
ooo
ooooo
ooooooo

View File

@ -413,7 +413,7 @@ static const FFlogo A[] = {
.lines = FASTFETCH_DATATEXT_LOGO_ARCO,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_GREEN,
FF_COLOR_FG_WHITE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
@ -425,7 +425,7 @@ static const FFlogo A[] = {
.lines = FASTFETCH_DATATEXT_LOGO_ARCO_SMALL,
.colors = {
FF_COLOR_FG_BLUE,
FF_COLOR_FG_GREEN,
FF_COLOR_FG_WHITE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,

View File

@ -422,8 +422,16 @@ void ffGenerateDiskJsonResult(FFDiskOptions* options, yyjson_mut_doc* doc, yyjso
yyjson_mut_obj_add_uint(doc, bytes, "used", item->bytesUsed);
yyjson_mut_val* files = yyjson_mut_obj_add_obj(doc, obj, "files");
yyjson_mut_obj_add_uint(doc, files, "total", item->filesTotal);
yyjson_mut_obj_add_uint(doc, files, "used", item->filesUsed);
if (item->filesTotal == 0 && item->filesUsed == 0)
{
yyjson_mut_obj_add_null(doc, files, "total");
yyjson_mut_obj_add_null(doc, files, "used");
}
else
{
yyjson_mut_obj_add_uint(doc, files, "total", item->filesTotal);
yyjson_mut_obj_add_uint(doc, files, "used", item->filesUsed);
}
yyjson_mut_obj_add_strbuf(doc, obj, "filesystem", &item->filesystem);
yyjson_mut_obj_add_strbuf(doc, obj, "mountpoint", &item->mountpoint);

View File

@ -159,16 +159,17 @@ void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments)
strbuf->length += (uint32_t) written;
}
void ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until)
const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until)
{
if(value == NULL)
return;
return NULL;
char* end = strchr(value, until);
if(end == NULL)
ffStrbufAppendS(strbuf, value);
else
ffStrbufAppendNS(strbuf, (uint32_t) (end - value), value);
return end;
}
void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...)

View File

@ -44,7 +44,7 @@ void ffStrbufAppendNS(FFstrbuf* strbuf, uint32_t length, const char* value);
void ffStrbufAppendTransformS(FFstrbuf* strbuf, const char* value, int(*transformFunc)(int));
FF_C_PRINTF(2, 3) void ffStrbufAppendF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments);
void ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until);
const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char until);
void ffStrbufPrependNS(FFstrbuf* strbuf, uint32_t length, const char* value);

View File

@ -1,54 +1,36 @@
//
// Include the necessary resources
//
#ifdef RC_INVOKED
#include <winuser.h>
#include <winver.h>
#include <ntdef.h>
#include "fastfetch_config.h"
#ifdef RC_INVOKED
//
// Set up debug information
//
#if DEBUG
#define VER_DEBUG VS_FF_DEBUG
#else
#define VER_DEBUG 0
#endif
#define FF_TO_STR1(str) #str
#define FF_TO_STR(str) FF_TO_STR1(str)
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "manifest.xml"
// ------- version info -------------------------------------------------------
VS_VERSION_INFO VERSIONINFO
FILEVERSION FASTFETCH_PROJECT_VERSION_MAJOR,FASTFETCH_PROJECT_VERSION_MINOR,FASTFETCH_PROJECT_VERSION_PATCH,FASTFETCH_PROJECT_VERSION_TWEAK_NUM
PRODUCTVERSION FASTFETCH_PROJECT_VERSION_MAJOR,FASTFETCH_PROJECT_VERSION_MINOR,FASTFETCH_PROJECT_VERSION_PATCH,FASTFETCH_PROJECT_VERSION_TWEAK_NUM
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS (VER_DEBUG|VS_FF_PRERELEASE)
FILEOS VOS_NT
FILETYPE VFT_APP
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0"
BEGIN
VALUE "Comments", FASTFETCH_PROJECT_HOMEPAGE_URL
VALUE "FileDescription", FF_TO_STR(FASTFETCH_TARGET_BINARY_NAME) " - " FASTFETCH_PROJECT_DESCRIPTION
VALUE "FileVersion", FASTFETCH_PROJECT_VERSION FASTFETCH_PROJECT_VERSION_TWEAK
VALUE "InternalName", FF_TO_STR(FASTFETCH_TARGET_BINARY_NAME) ".exe"
VALUE "LegalCopyright", FASTFETCH_PROJECT_LICENSE
VALUE "OriginalFilename", FF_TO_STR(FASTFETCH_TARGET_BINARY_NAME) ".exe"
VALUE "ProductName", FASTFETCH_PROJECT_NAME
VALUE "ProductVersion", FASTFETCH_PROJECT_VERSION FASTFETCH_PROJECT_VERSION_TWEAK
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409,1252
END
END
FILEVERSION FASTFETCH_PROJECT_VERSION_MAJOR,FASTFETCH_PROJECT_VERSION_MINOR,FASTFETCH_PROJECT_VERSION_PATCH,FASTFETCH_PROJECT_VERSION_TWEAK_NUM
PRODUCTVERSION FASTFETCH_PROJECT_VERSION_MAJOR,FASTFETCH_PROJECT_VERSION_MINOR,FASTFETCH_PROJECT_VERSION_PATCH,FASTFETCH_PROJECT_VERSION_TWEAK_NUM
FILEOS VOS_NT
FILETYPE VFT_APP
{
BLOCK "StringFileInfo" {
BLOCK "040904b0" {
VALUE "Comments", FASTFETCH_PROJECT_DESCRIPTION
VALUE "FileDescription", FF_TO_STR(FASTFETCH_TARGET_BINARY_NAME)
VALUE "FileVersion", FASTFETCH_PROJECT_VERSION FASTFETCH_PROJECT_VERSION_TWEAK
VALUE "InternalName", FF_TO_STR(FASTFETCH_TARGET_BINARY_NAME)
VALUE "LegalCopyright", FASTFETCH_PROJECT_LICENSE
VALUE "OriginalFilename", FF_TO_STR(FASTFETCH_TARGET_BINARY_NAME) ".exe"
VALUE "ProductName", FASTFETCH_PROJECT_NAME " - " FASTFETCH_PROJECT_DESCRIPTION
VALUE "ProductVersion", FASTFETCH_PROJECT_VERSION FASTFETCH_PROJECT_VERSION_TWEAK
VALUE "CompanyName", FASTFETCH_PROJECT_HOMEPAGE_URL
}
}
BLOCK "VarFileInfo" {
VALUE "Translation", 0x0409, 1200
}
}
#endif