Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use semicolon as file path separator for lua_load #2154

Merged
merged 4 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion doc/config_settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,18 @@ values:
- function_name
- [function arguments]
- name: lua_load
desc: Loads the Lua scripts separated by spaces.
desc: |-
List of Lua script paths to load at startup in order to provide Lua
functions for other hooks. Listed files are loaded (executed) before
'lua_startup_hook' and can (but shouldn't) run code in global scope.

Paths are ';' (semicolon) separated, and can be relative to the config
file path, or absolute.

The paths were previously ' ' (space) separated, this functionality is
still supported if ';' isn't found, but is deprecated and will be removed
in future versions. Empty paths are skipped so './example file.lua;' is
valid.
- name: lua_mouse_hook
desc: |-
This function, if defined, will be called by Conky upon receiving mouse
Expand Down
10 changes: 7 additions & 3 deletions src/common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,14 @@ std::filesystem::path to_real_path(const std::string &source) {
wordexp_t p;
char **w;
int i;
const char *csource = source.c_str();
if (wordexp(csource, &p, 0) != 0) {
return std::string();
std::string checked = std::string(source);
std::string::size_type n = 0;
while ((n = checked.find(" ", n)) != std::string::npos) {
checked.replace(n, 1, "\\ ");
n += 2;
}
const char *csource = source.c_str();
if (wordexp(checked.c_str(), &p, 0) != 0) { return std::string(); }
w = p.we_wordv;
const char *resolved_path = strdup(w[0]);
wordfree(&p);
Expand Down
37 changes: 2 additions & 35 deletions src/conky.cc
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@
#include "data/timeinfo.h"
#include "data/top.h"
#include "logging.h"
#include "lua/llua.h"
#include "output/nc.h"

#ifdef BUILD_MYSQL
Expand All @@ -134,6 +133,7 @@
#include "data/network/ccurl_thread.h"
#endif /* BUILD_CURL */

#include "lua/llua.h"
#include "lua/lua-config.hh"
#include "lua/setting.hh"
#include "output/display-output.hh"
Expand Down Expand Up @@ -1985,40 +1985,6 @@ void load_config_file() {
lua::stack_sentry s(l);
l.checkstack(2);

// Extend lua package.path so scripts can use relative paths
{
struct stat file_stat {};

std::string path_ext;

// add XDG directory to lua path
auto xdg_path =
std::filesystem::path(to_real_path(XDG_CONFIG_FILE)).parent_path();
if (stat(xdg_path.c_str(), &file_stat) == 0) {
path_ext.push_back(';');
path_ext.append(xdg_path);
path_ext.append("/?.lua");
}

auto parent_path = current_config.parent_path();
if (xdg_path != parent_path && stat(path_ext.c_str(), &file_stat) == 0) {
path_ext.push_back(';');
path_ext.append(parent_path);
path_ext.append("/?.lua");
}

l.getglobal("package");
l.getfield(-1, "path");

auto path = l.tostring(-1);
path.append(path_ext);
l.pop();
l.pushstring(path.c_str());

l.setfield(-2, "path");
l.pop();
}

try {
#ifdef BUILD_BUILTIN_CONFIG
if (current_config == builtin_config_magic) {
Expand Down Expand Up @@ -2171,6 +2137,7 @@ void initialisation(int argc, char **argv) {
set_default_configurations();

set_current_config();
llua_init();
load_config_file();

/* handle other command line arguments */
Expand Down
148 changes: 108 additions & 40 deletions src/lua/llua.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@
*/
#include "config.h"

#include "build.h"
#include <cstring>
#include <filesystem>
#include <sstream>

#include "../conky.h"
#include "../geometry.h"
#include "llua.h"
#include "../logging.h"
#include "build.h"
#include "llua.h"

#ifdef BUILD_GUI
#include "../output/gui.h"

#ifdef BUILD_X11
#include "x11-settings.h"
#include "../output/x11.h"
#include "x11-settings.h"
#endif /* BUILD_X11 */

#ifdef BUILD_MOUSE_EVENTS
Expand Down Expand Up @@ -75,13 +79,26 @@ class lua_load_setting : public conky::simple_config_setting<std::string> {

if (init) {
std::string files = do_convert(l, -1).first;
while (!files.empty()) {
std::string::size_type pos = files.find(' ');
if (pos > 0) {
std::string file(files, 0, pos);
llua_load(file.c_str());

// Split file names into separate `\0` strings
if (files.find(';') != std::string::npos) {
for (auto &ch : files) {
if (ch == ';') { ch = '\0'; }
}
} else {
// TODO: Remove space-delimited file name handling in 3 years (2028.)
for (auto &ch : files) {
if (ch == ' ') { ch = '\0'; }
}
files.erase(0, pos == std::string::npos ? pos : pos + 1);
}

const char *start = files.c_str();
const char *end = start + files.size();
while (start < end) {
if (*start != '\0') { // Skip empty strings
llua_load(start);
}
start += strlen(start) + 1;
}
}

Expand All @@ -94,7 +111,6 @@ class lua_load_setting : public conky::simple_config_setting<std::string> {
#ifdef HAVE_SYS_INOTIFY_H
llua_rm_notifies();
#endif /* HAVE_SYS_INOTIFY_H */
if (lua_L == nullptr) { return; }
lua_close(lua_L);
lua_L = nullptr;
}
Expand Down Expand Up @@ -171,15 +187,50 @@ void llua_init() {

/* add our library path to the lua package.cpath global var */
luaL_openlibs(lua_L);
lua_getglobal(lua_L, "package");
lua_getfield(lua_L, -1, "cpath");
lua_getglobal(lua_L, "package"); // stack: package
lua_getfield(lua_L, -1, "cpath"); // stack: package.cpath, package

old_path = std::string(lua_tostring(lua_L, -1));
new_path = libs + old_path;

lua_pushstring(lua_L, new_path.c_str());
lua_setfield(lua_L, -3, "cpath");
lua_pop(lua_L, 2);
lua_pushstring(lua_L,
new_path.c_str()); // stack: new_path, package.cpath, package
lua_setfield(lua_L, -3, "cpath"); // stack: package.cpath, package
lua_pop(lua_L, 1); // stack: package

/* Add config file and XDG paths to package.path so scripts can load other
* scripts from relative paths */
{
struct stat file_stat{};

std::string path_ext;

// add XDG directory to lua path
auto xdg_path =
std::filesystem::path(to_real_path(XDG_CONFIG_FILE)).parent_path();
if (stat(xdg_path.c_str(), &file_stat) == 0) {
path_ext.append(xdg_path);
path_ext.append("/?.lua");
path_ext.push_back(';');
}

auto parent_path = current_config.parent_path();
if (xdg_path != parent_path && stat(path_ext.c_str(), &file_stat) == 0) {
path_ext.append(parent_path);
path_ext.append("/?.lua");
path_ext.push_back(';');
}

lua_getfield(lua_L, -1, "path"); // stack: package.path, package
old_path = std::string(lua_tostring(lua_L, -1));
new_path = path_ext + old_path;

lua_pushstring(lua_L,
new_path.c_str()); // stack: new_path, package.path, package
lua_setfield(lua_L, -3, "path"); // stack: package.path, package
lua_pop(lua_L, 1); // stack: package
}
lua_pop(lua_L, 1); // stack is empty

lua_pushstring(lua_L, PACKAGE_NAME " " VERSION " compiled for " BUILD_ARCH);
lua_setglobal(lua_L, "conky_build_info");
Expand Down Expand Up @@ -216,17 +267,46 @@ inline bool file_exists(const char *path) {
void llua_load(const char *script) {
int error;

std::string path = to_real_path(script);
std::filesystem::path path = to_real_path(script);

if (!file_exists(path.c_str())) {
NORM_ERR("llua_load: specified script file '%s' doesn't exist",
path.c_str());
// return without initializing lua_L because other parts of the code rely
// on it being null if the script is not loaded
return;
}
bool found_alternative = false;

// Try resolving file name by using files in lua path:
lua_getglobal(lua_L, "package"); // stack: package
lua_getfield(lua_L, -1, "path"); // stack: package.path, package
auto lua_path = lua_tostring(lua_L, -1);
lua_pop(lua_L, 2); // stack is empty

std::stringstream path_stream(lua_path);
std::string current;
while (std::getline(path_stream, current, ';')) {
// lua_load conky variable accepts full file names, so replace "?.lua"
// with "?" to ensure file names don't get the unexpected .lua suffix; but
// modules with init.lua will still work.
size_t substitute_pos = current.find("?.lua");
if (substitute_pos != std::string::npos) {
current.replace(substitute_pos, 5, "?");
}

llua_init();
substitute_pos = current.find('?');
if (substitute_pos == std::string::npos) { continue; }
current.replace(substitute_pos, 1, script);
path = to_real_path(current);

if (file_exists(path.c_str())) {
found_alternative = true;
break;
}
}

if (!found_alternative) {
NORM_ERR("llua_load: specified script file '%s' doesn't exist", script);
// return without initializing lua_L because other parts of the code rely
// on it being null if the script is not loaded
return;
}
}

error = luaL_dofile(lua_L, path.c_str());
if (error != 0) {
Expand Down Expand Up @@ -347,8 +427,6 @@ static char *llua_getstring(const char *args) {
char *func;
char *ret = nullptr;

if (lua_L == nullptr) { return nullptr; }

func = llua_do_call(args, 1);
if (func != nullptr) {
if (lua_isstring(lua_L, -1) == 0) {
Expand Down Expand Up @@ -392,8 +470,6 @@ static char *llua_getstring_read(const char *function, const char *arg)
static int llua_getnumber(const char *args, double *ret) {
char *func;

if (lua_L == nullptr) { return 0; }

func = llua_do_call(args, 1);
if (func != nullptr) {
if (lua_isnumber(lua_L, -1) == 0) {
Expand Down Expand Up @@ -489,32 +565,30 @@ void llua_set_number(const char *key, double value) {
}

void llua_startup_hook() {
if ((lua_L == nullptr) || lua_startup_hook.get(*state).empty()) { return; }
if (lua_startup_hook.get(*state).empty()) { return; }
llua_do_call(lua_startup_hook.get(*state).c_str(), 0);
}

void llua_shutdown_hook() {
if ((lua_L == nullptr) || lua_shutdown_hook.get(*state).empty()) { return; }
if (lua_shutdown_hook.get(*state).empty()) { return; }
llua_do_call(lua_shutdown_hook.get(*state).c_str(), 0);
}

#ifdef BUILD_GUI
void llua_draw_pre_hook() {
if ((lua_L == nullptr) || lua_draw_hook_pre.get(*state).empty()) { return; }
if (lua_draw_hook_pre.get(*state).empty()) { return; }
llua_do_call(lua_draw_hook_pre.get(*state).c_str(), 0);
}

void llua_draw_post_hook() {
if ((lua_L == nullptr) || lua_draw_hook_post.get(*state).empty()) { return; }
if (lua_draw_hook_post.get(*state).empty()) { return; }
llua_do_call(lua_draw_hook_post.get(*state).c_str(), 0);
}

#ifdef BUILD_MOUSE_EVENTS
template <typename EventT>
bool llua_mouse_hook(const EventT &ev) {
if ((lua_L == nullptr) || lua_mouse_hook.get(*state).empty()) {
return false;
}
if (lua_mouse_hook.get(*state).empty()) { return false; }
const std::string raw_hook_name = lua_mouse_hook.get(*state);
std::string hook_name;
if (raw_hook_name.rfind("conky_", 0) == 0) {
Expand Down Expand Up @@ -579,7 +653,6 @@ void llua_set_userdata(const char *key, const char *type, void *value) {
}

void llua_setup_window_table(conky::rect<int> text_rect) {
if (lua_L == nullptr) { return; }
lua_newtable(lua_L);

#ifdef BUILD_X11
Expand Down Expand Up @@ -611,8 +684,6 @@ void llua_setup_window_table(conky::rect<int> text_rect) {
}

void llua_update_window_table(conky::rect<int> text_rect) {
if (lua_L == nullptr) { return; }

lua_getglobal(lua_L, "conky_window");
if (lua_isnil(lua_L, -1)) {
/* window table isn't populated yet */
Expand All @@ -635,7 +706,6 @@ void llua_update_window_table(conky::rect<int> text_rect) {
#endif /* BUILD_GUI */

void llua_setup_info(struct information *i, double u_interval) {
if (lua_L == nullptr) { return; }
lua_newtable(lua_L);

llua_set_number("update_interval", u_interval);
Expand All @@ -645,8 +715,6 @@ void llua_setup_info(struct information *i, double u_interval) {
}

void llua_update_info(struct information *i, double u_interval) {
if (lua_L == nullptr) { return; }

lua_getglobal(lua_L, "conky_info");
if (lua_isnil(lua_L, -1)) {
/* window table isn't populated yet */
Expand Down
1 change: 1 addition & 0 deletions src/lua/llua.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extern "C" {
void llua_inotify_query(int wd, int mask);
#endif /* HAVE_SYS_INOTIFY_H */

void llua_init();
void llua_startup_hook(void);
void llua_shutdown_hook(void);

Expand Down
Loading