Editor: improve performance of version detection

This commit is contained in:
李通洲 2024-08-20 16:37:54 +08:00 committed by Carter Li
parent 8559ab2dcd
commit 4860bc35d6
5 changed files with 154 additions and 49 deletions

View File

@ -401,6 +401,7 @@ set(LIBFASTFETCH_SRC
src/util/base64.c
src/util/FFlist.c
src/util/FFstrbuf.c
src/util/path.c
src/util/platform/FFPlatform.c
src/util/smbiosHelper.c
)

View File

@ -1,17 +1,45 @@
#include "editor.h"
#include "common/processing.h"
#include "util/stringUtils.h"
#include "util/path.h"
#include "util/linux/elf.h"
#include <stdlib.h>
#ifdef _WIN32
#include <windows.h>
static inline char* realpath(const char* restrict file_name, char* restrict resolved_name)
{
return _fullpath(resolved_name, file_name, _MAX_PATH);
}
#endif
#if __linux__ || __FreeBSD__
static bool extractNvimVersion(const char* str, uint32_t len, void* userdata)
{
if (len < strlen("NVIM v0.0.0")) return true;
if (!ffStrStartsWith(str, "NVIM v")) return true;
ffStrbufSetS((FFstrbuf*) userdata, str + strlen("NVIM v"));
return false;
}
static bool extractVimVersion(const char* str, uint32_t len, void* userdata)
{
if (len < strlen("VIM - Vi IMproved 0.0")) return true;
if (!ffStrStartsWith(str, "VIM - Vi IMproved ")) return true;
ffStrbufSetS((FFstrbuf*) userdata, str + strlen("VIM - Vi IMproved "));
ffStrbufSubstrBeforeFirstC(userdata, ' ');
return false;
}
static bool extractNanoVersion(const char* str, uint32_t len, void* userdata)
{
if (len < strlen("GNU nano 0.0")) return true;
if (!ffStrStartsWith(str, "GNU nano ")) return true;
ffStrbufSetS((FFstrbuf*) userdata, str + strlen("GNU nano "));
return false;
}
#endif
const char* ffDetectEditor(FFEditorResult* result)
{
ffStrbufSetS(&result->name, getenv("VISUAL"));
@ -26,35 +54,15 @@ const char* ffDetectEditor(FFEditorResult* result)
return "$VISUAL or $EDITOR not set";
}
if (!instance.config.general.detectVersion) return NULL;
#ifndef _WIN32
if (result->name.chars[0] != '/')
{
if (ffProcessAppendStdOut(&result->path, (char* const[]){
FASTFETCH_TARGET_DIR_USR "/bin/which",
result->name.chars,
NULL,
}) != NULL || result->path.length == 0)
return NULL;
}
#else
if (!(result->name.length > 3 && ffCharIsEnglishAlphabet(result->name.chars[0]) && result->name.chars[1] == ':' && result->name.chars[2] == '\\'))
{
char buf[32];
uint32_t len = GetSystemDirectoryA(buf, sizeof(buf));
if (len < strlen("C:\\WINDOWS\\system32")) return NULL;
strncpy(buf + len, "\\where.exe", sizeof(buf) - len);
if (ffProcessAppendStdOut(&result->path, (char* const[]){
buf,
result->name.chars,
NULL,
}) != NULL || result->path.length == 0)
return NULL;
}
#endif
else
if (ffIsAbsolutePath(result->name.chars))
ffStrbufSet(&result->path, &result->name);
else
{
const char* error = ffFindExecutableInPath(result->name.chars, &result->path);
if (error) return error;
}
if (!instance.config.general.detectVersion) return NULL;
char buf[PATH_MAX + 1];
if (!realpath(result->path.chars, buf))
@ -82,6 +90,17 @@ const char* ffDetectEditor(FFEditorResult* result)
#endif
}
#if __linux__ || __FreeBSD__
if (ffStrbufEqualS(&result->exe, "nvim"))
ffElfExtractStrings(buf, extractNvimVersion, &result->version);
else if (ffStrbufEqualS(&result->exe, "vim"))
ffElfExtractStrings(buf, extractVimVersion, &result->version);
else if (ffStrbufEqualS(&result->exe, "nano"))
ffElfExtractStrings(buf, extractNanoVersion, &result->version);
if (result->version.length > 0) return NULL;
#endif
const char* param = NULL;
if (
ffStrbufEqualS(&result->exe, "nano") ||

View File

@ -9,49 +9,72 @@
#include <libelf.h>
#include <fcntl.h>
struct FFElfData {
FF_LIBRARY_SYMBOL(elf_version)
FF_LIBRARY_SYMBOL(elf_begin)
FF_LIBRARY_SYMBOL(elf_getshdrstrndx)
FF_LIBRARY_SYMBOL(elf_nextscn)
FF_LIBRARY_SYMBOL(elf64_getshdr)
FF_LIBRARY_SYMBOL(elf32_getshdr)
FF_LIBRARY_SYMBOL(elf_getdata)
FF_LIBRARY_SYMBOL(elf_strptr)
FF_LIBRARY_SYMBOL(elf_end)
bool inited;
} elfData;
const char* ffElfExtractStrings(const char* elfFile, bool (*cb)(const char* str, uint32_t len, void* userdata), void* userdata)
{
FF_LIBRARY_LOAD(libelf, &instance.config.library.libelf, "dlopen libelf" FF_LIBRARY_EXTENSION " failed", "libelf" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_version)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_begin)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_getshdrstrndx)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_nextscn)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf64_getshdr)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf32_getshdr)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_getdata)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_strptr)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libelf, elf_end)
if (!elfData.inited)
{
elfData.inited = true;
FF_LIBRARY_LOAD(libelf, &instance.config.library.libelf, "dlopen libelf" FF_LIBRARY_EXTENSION " failed", "libelf" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_version)
if (elfData.ffelf_version(EV_CURRENT) == EV_NONE) return "elf_version() failed";
if (ffelf_version(EV_CURRENT) == EV_NONE) return "elf_version() failed";
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_begin)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_getshdrstrndx)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_nextscn)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf64_getshdr)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf32_getshdr)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_getdata)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_strptr)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_end)
libelf = NULL;
}
if (elfData.ffelf_end == NULL)
return "load libelf failed";
FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY, 0);
if (fd < 0) return "open() failed";
Elf* elf = ffelf_begin(fd, ELF_C_READ, NULL);
Elf* elf = elfData.ffelf_begin(fd, ELF_C_READ, NULL);
if (elf == NULL) return "elf_begin() failed";
size_t shstrndx = 0;
if (ffelf_getshdrstrndx(elf, &shstrndx) < 0)
if (elfData.ffelf_getshdrstrndx(elf, &shstrndx) < 0)
{
ffelf_end(elf);
elfData.ffelf_end(elf);
return "elf_getshdrstrndx() failed";
}
Elf_Scn* scn = NULL;
while ((scn = ffelf_nextscn(elf, scn)) != NULL)
while ((scn = elfData.ffelf_nextscn(elf, scn)) != NULL)
{
Elf64_Shdr* shdr64 = ffelf64_getshdr(scn);
Elf64_Shdr* shdr64 = elfData.ffelf64_getshdr(scn);
Elf32_Shdr* shdr32 = NULL;
if (shdr64 == NULL)
{
shdr32 = ffelf32_getshdr(scn);
shdr32 = elfData.ffelf32_getshdr(scn);
if (shdr32 == NULL) continue;
}
const char* name = ffelf_strptr(elf, shstrndx, shdr64 ? shdr64->sh_name : shdr32->sh_name);
const char* name = elfData.ffelf_strptr(elf, shstrndx, shdr64 ? shdr64->sh_name : shdr32->sh_name);
if (name == NULL || !ffStrEquals(name, ".rodata")) continue;
Elf_Data* data = ffelf_getdata(scn, NULL);
Elf_Data* data = elfData.ffelf_getdata(scn, NULL);
if (data == NULL) continue;
for (size_t off = 0; off < data->d_size; ++off)
@ -69,7 +92,7 @@ const char* ffElfExtractStrings(const char* elfFile, bool (*cb)(const char* str,
break;
}
ffelf_end(elf);
elfData.ffelf_end(elf);
return NULL;
}

56
src/util/path.c Normal file
View File

@ -0,0 +1,56 @@
#include "path.h"
#include "common/io/io.h"
#include "util/stringUtils.h"
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result)
{
char* path = getenv("PATH");
if(!path)
return "$PATH not set";
#ifdef _WIN32
const bool appendExe = !ffStrEndsWithIgnCase(name, ".exe");
#endif
for (char* token = NULL; (token = strchr(path,
#ifdef _WIN32
';'
#else
':'
#endif
)) != NULL; path = token + 1)
{
ffStrbufSetNS(result, (uint32_t)(token - path), path);
ffStrbufEnsureEndsWithC(result,
#ifdef _WIN32
'\\'
#else
'/'
#endif
);
ffStrbufAppendS(result, name);
#ifdef _WIN32
if (appendExe) ffStrbufAppendS(result, ".exe");
if (!ffPathExists(result->chars, FF_PATHTYPE_FILE))
continue;
#else
struct stat st;
if (stat(result->chars, &st) < 0 || !(st.st_mode & S_IXUSR))
continue;
#endif
return NULL;
}
ffStrbufClear(result);
return "Executable not found";
}
bool ffIsAbsolutePath(const char* path)
{
#ifdef _WIN32
return ffCharIsEnglishAlphabet(path[0]) && path[1] == ':' && (path[2] == '\\' || path[2] == '/');
#else
return path[0] == '/';
#endif
}

6
src/util/path.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include "fastfetch.h"
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result);
bool ffIsAbsolutePath(const char* path);