This document explains Termi's code and relevant things when using it.
Termi-Commands
folder/directory - core commandsTermi-GUI
folder/directory - GUITermi-Main
folder/directory - call GUI
- Add language name in English in
language_id
vector intranslation.hpp
. - Don't forget to capitalize its name and sort it alphabetically, but keep English first!
- Add translated text to vector in map **making sure it's aligned as in
language_id
vector. - Add button to change language in
ChooseLanguageDialog
dialog inimgui.cpp
:
if (ImGui::Button("English name / Native name") || (ImGui::IsItemFocused() && ImGui::IsKeyPressed(ImGuiKey_Enter)))
{
vrenderer[vrenderer_id]->language = "English name";
}
default
- Basic Latin + Latin Supplementkorean
chinese_full
chinese_simplified_common
japanese
cyrillic
thai
vietnamese
latin-ex-a
- Basic Latin + Latin supplement + Latin extended A; only usable withSweet16.tff
located infont
folder/directory accessible toTermi-Main
executable
- Add function name in
Export.h
inTermi-Commands
project. - Add C++ code in
Commands.cpp
inTermi-Commands
project. - See example:
extern "C"
{
EXPORT example(const std::vector<std::string>& vect);
}; /* Export.h */
VOID example(const std::vector<std::string>& vect)
{
/* AddLog is "printf" function of console */
/* Call Status() function at the end */
int number = 30;
AddLog("Number is: %d\n", number);
Status(0);
} /* Commands.cpp */
- Create new Visual Studio DLL project.
- Copy
AddLog
andLoadDynamicLibrary
functions.
#pragma warning(disable: 4996)
#pragma comment(lib, "Advapi32.lib")
#pragma comment(lib, "Kernel32.lib")
template <typename T>
int LoadDynamicLibrary(const char* path, const char* function, T argument)
{
typedef int(__cdecl* MYPROC)(T);
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to the DLL module
hinstLib = LoadLibrary(LPCSTR(path));
// If the handle is valid, try to get the function address.
if (hinstLib != NULL)
{
ProcAdd = (MYPROC)GetProcAddress(hinstLib, function);
// If the function address is valid, call the function.
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd)(argument);
}
else
{
printf("Error loading function '%s' from '%s'!\n", function, path);
return 1;
}
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
}
// If unable to call the DLL function, use an alternative.
if (!fRunTimeLinkSuccess)
{
printf("Error loading function '%s' from '%s'!\n", function, path);
return 1;
}
return 0;
}
// Explicitly instantiate a template if `LoadDynamicLibrary()` function has to be called from extern "C" block
template int LoadDynamicLibrary<const char*>(const char* path, const char* function, const char* argument);
void AddLog(std::string fmt, ...)
{
// FIXME-OPT
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt.c_str(), args);
buf[sizeof(buf) - 1] = 0;
va_end(args);
LoadDynamicLibrary("/path/", "AddLog", buf);
}
- Mark function to be called from program as
_declspec(dllexport)
stuff insideextern "C"
in .h file and asvoid __cdecl
in .cpp file
extern "C"
{
__declspec(dllexport) void __cdecl program(const char* arguments);
}; /* .h file */
void __cdecl program(const char* arguments); /* .cpp file */
- Replace all other functions for printing to console (like
printf
,std::cout
, etc.) toAddLog
function.AddLog
works likeprintf
. - Compile and use Termi's
loadtp
command to test it!
- Create new project with
CMakeLists.txt
file similar toTermi-Commands
project - Copy
AddLog
andLoadDynamicLibrary
functions.
template <typename T>
int LoadDynamicLibrary(const char* path, const char* function, T argument)
{
void *handle;
void (*func)(T);
char *error;
handle = dlopen(path, RTLD_LAZY);
if (!handle)
{
fputs (dlerror(), stderr);
puts(" ");
return 1;
}
func = reinterpret_cast<void (*)(T)>(dlsym(handle, function));
if ((error = dlerror()) != NULL)
{
fputs(error, stderr);
return 1;
}
(*func)(argument);
dlclose(handle);
return 0;
}
// This explicit template instantiation is making `LoadDynamicLibrary` function available from extern "C" block
template int LoadDynamicLibrary<const char*>(const char* path, const char* function, const char* argument);
void AddLog(std::string fmt, ...)
{
// FIXME-OPT
char buf[1024];
va_list args;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt.c_str(), args);
buf[sizeof(buf) - 1] = 0;
va_end(args);
LoadDynamicLibrary("/path/", "AddLog", buf);
}
- Put public function inside
extern "C"
in .h file.
extern "C"
{
void program(const char* arguments);
}; /* .h file */
void program(const char* arguments); /* .cpp file */
- Replace all other functions for printing to console (like
printf
,std::cout
, etc.) toAddLog
function.AddLog
works likeprintf
. - Compile and use Termi's
loadtp
command to test it!
Passed argument to a third party commands/applications using loadtp
command is one combined string. Do parsing inside your command/application, arguments are separated by space!
- Create new Rust library by using cargo -
cargo new --lib name
. - Change
Cargo.toml
content to (changename
andversion
):
[package]
name = "your package name"
version = "version"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
libloading = "0.7"
- Change
lib.rs
content to (change path to .dll or .so file):
#![allow(non_snake_case)]
use libloading::{Library, Symbol};
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
/// `printf()` for Termi's console
fn AddLog(fmt: &CStr) {
unsafe {
let lib = Library::new("path do .dll or .so file").unwrap();
let foo = lib
.get::<Symbol<extern "C" fn(*const c_char)>>(b"AddLog")
.unwrap();
foo(fmt.as_ptr());
}
}
/// Separate string into arguments intended for this Rust program
///
/// Returns vector of `CString`
fn GetArguments(arg: *const c_char) -> Vec<CString> {
let mut vec = Vec::new();
let arg_buf = unsafe { CStr::from_ptr(arg) };
let arg_str = arg_buf.to_str().unwrap();
for word in arg_str.split(' ') {
let c_string = CString::new(word).expect("Failed to create CString");
vec.push(c_string);
}
return vec;
}
#[no_mangle]
pub extern "C" fn rust_function(arg: *const c_char) {
/* your code */
let text = CString::new("Example how to print text to Termi's console from Rust").expect("CString::new failed!");
AddLog(&text);
}
vect[0]; /* name of command */
vect[i]; /* argument while `i` represents order of argument */
In development.