Skip to content

Commit

Permalink
Add lo_set_external_plugin_paths()
Browse files Browse the repository at this point in the history
To allow the external plugins paths to be provided, overriding the
defaults.
  • Loading branch information
Ortham committed Apr 20, 2023
1 parent 87de3b4 commit 2f56caa
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 1 deletion.
44 changes: 43 additions & 1 deletion ffi/src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ use loadorder::GameSettings;
use loadorder::WritableLoadOrder;

use crate::constants::*;
use crate::helpers::{error, handle_error, to_c_string, to_c_string_array, to_str};
use crate::helpers::{
error, handle_error, to_c_string, to_c_string_array, to_path_buf_vec, to_str,
};

/// A structure that holds all game-specific data used by libloadorder.
///
Expand Down Expand Up @@ -354,3 +356,43 @@ pub unsafe extern "C" fn lo_get_active_plugins_file_path(
})
.unwrap_or(LIBLO_ERROR_PANICKED)
}

/// Sets the external plugin paths to be recognised by the given handle.
///
/// If the load order contains plugins that are installed outside of the game's plugins directory,
/// this function can be used to provide the paths to those plugins so that libloadorder is able to
/// find them.
///
/// If external plugins exist, this function must be called before performing any operations on
/// the load order to avoid any unexpected behaviour.
///
/// Returns `LIBLO_OK` if successful, otherwise a `LIBLO_ERROR_*` code is returned.
#[no_mangle]
pub unsafe extern "C" fn lo_set_external_plugin_paths(
handle: lo_game_handle,
paths: *const *const c_char,
num_paths: size_t,
) -> c_uint {
catch_unwind(|| {
if handle.is_null() || paths.is_null() {
return error(LIBLO_ERROR_INVALID_ARGS, "Null pointer passed");
}

let mut handle = match (*handle).write() {
Err(e) => return error(LIBLO_ERROR_POISONED_THREAD_LOCK, &e.to_string()),
Ok(h) => h,
};

let plugin_paths = match to_path_buf_vec(paths, num_paths) {
Ok(x) => x,
Err(x) => return error(x, "A filename contained a null byte"),
};

handle
.game_settings_mut()
.set_external_plugin_paths(plugin_paths);

LIBLO_OK
})
.unwrap_or(LIBLO_ERROR_PANICKED)
}
11 changes: 11 additions & 0 deletions ffi/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use std::ffi::{CStr, CString};
use std::io;
use std::mem;
use std::path::PathBuf;
use std::slice;

use libc::{c_char, c_uint, size_t};
Expand Down Expand Up @@ -114,3 +115,13 @@ pub unsafe fn to_str_vec<'a>(
.map(|c| to_str(*c))
.collect()
}

pub unsafe fn to_path_buf_vec(
array: *const *const c_char,
array_size: usize,
) -> Result<Vec<PathBuf>, u32> {
slice::from_raw_parts(array, array_size)
.iter()
.map(|c| to_str(*c).map(PathBuf::from))
.collect()
}
12 changes: 12 additions & 0 deletions ffi/tests/ffi.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,17 @@ void test_lo_get_active_plugins_file_path() {
lo_destroy_handle(handle);
}

void test_lo_set_external_plugin_paths() {
printf("testing lo_set_external_plugin_paths()...\n");
lo_game_handle handle = create_handle();

const char * paths[] = { "Blank.esm" };
unsigned int return_code = lo_set_external_plugin_paths(handle, paths, 1);

assert(return_code == 0);
lo_destroy_handle(handle);
}

void test_lo_set_active_plugins() {
printf("testing lo_set_active_plugins()...\n");
lo_game_handle handle = create_handle();
Expand Down Expand Up @@ -300,6 +311,7 @@ int main(void) {
test_lo_fix_plugin_lists();
test_lo_get_implicitly_active_plugins();
test_lo_get_active_plugins_file_path();
test_lo_set_external_plugin_paths();

test_lo_set_active_plugins();
test_lo_get_active_plugins();
Expand Down
12 changes: 12 additions & 0 deletions ffi/tests/ffi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@ void test_lo_get_active_plugins_file_path() {
lo_destroy_handle(handle);
}

void test_lo_set_external_plugin_paths() {
printf("testing lo_set_external_plugin_paths()...\n");
lo_game_handle handle = create_handle();

const char * paths[] = { "Blank.esm" };
unsigned int return_code = lo_set_external_plugin_paths(handle, paths, 1);

assert(return_code == 0);
lo_destroy_handle(handle);
}

void test_lo_set_active_plugins() {
printf("testing lo_set_active_plugins()...\n");
lo_game_handle handle = create_handle();
Expand Down Expand Up @@ -325,6 +336,7 @@ int main(void) {
test_lo_fix_plugin_lists();
test_lo_get_implicitly_active_plugins();
test_lo_get_active_plugins_file_path();
test_lo_set_external_plugin_paths();

test_lo_set_active_plugins();
test_lo_get_active_plugins();
Expand Down

0 comments on commit 2f56caa

Please sign in to comment.