Just drop a Pull Request :)
- Use CRLF for Windows code, LF for (GNU/)Linux code (`git config --global core.autocrlf).
- Use following style WITH LOGIC, check labels:
- Use spaces, size 4.
Please run zip_file.ps1
after you verified that code can run on Windows!
[LABEL NAME] Name of Pull Request
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";
}
- 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.program!
- 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);
}
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.program!
vect[0]; /* name of command */
vect[i]; /* argument while `i` represents order of argument */
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
Coding style shown below only applies to C and C++. If you use Rust, please use Rust's coding style!
- Line width much be at most 100 characters.
- Use spaces, spaces size MUST BE 4!
- Indent both a case label and the case statement of a switch statement.
Right:
switch (Condition)
{
case 1:
DoSomething();
break;
}
Wrong:
switch (Condition)
{
case 1:
DoSomething();
break;
}
When a function call does not fit onto a line, align arguments like this:
FunctionCall(arg1,
arg2,
arg3);
When making new functions, use an return type. Right:
int func() {}
Wrong:
func() {}
- Do not use spaces around unary operators.
Right: i++
Wrong: i ++
- Place spaces around binary and ternary operators.
Right: a = b + c;
Wrong: a=b+c;
- Do not place spaces before comma and semicolon.
Right:
for (int i = 0; i < 5; i++)
DoSomething();
func1(a, b);
Wrong:
for (int i = 0 ; i < 5 ; i++)
DoSomething();
func1(a , b) ;
- Place spaces between control statements and their parentheses.
Right:
if (Condition)
DoSomething();
Wrong:
if(Condition)
DoSomething();
- Do not place spaces between a function and its parentheses, or between a parenthesis and its content.
Right:
func(a, b);
Wrong:
func (a, b);
func( a, b );
- Each statement should get its own line.
Right:
x++;
y++;
if (Condition)
{
DoSomething();
}
Also right but don't use it often
if (Condition) DoSomething();
if (Condition)
DoSomething();
Wrong:
x++; y++;
- Always put braces ({ and }) on their own lines.
- One-line control clauses may use braces, but this is not a requirement. An exception are one-line control clauses including additional comments.
Right:
if (Condition)
DoSomething();
if (Condition)
{
DoSomething();
}
if (Condition)
{
// This is a comment
DoSomething();
}
if (Condition)
DoSomething();
else
DoSomethingElse();
if (Condition)
{
DoSomething();
}
else
{
DoSomethingElse();
YetAnother();
}
Wrong:
if (Condition) {
DoSomething();
}
if (Condition)
// This is a comment
DoSomething();
if (Condition)
DoSomething();
else
{
DoSomethingElse();
YetAnother();
}
- Don’t use inverse logic in control clauses.
Right: if (i == 1)
Wrong: if (1 == i)
- Avoid too many levels of cascaded control structures. Prefer a “linear style” over a “tree style”. Use goto when it helps to make the code cleaner (e.g. for cleanup paths).
Right:
if (!func1())
return;
i = func2();
if (i == 0)
return;
j = func3();
if (j == 1)
return;
…
Wrong:
if (func1())
{
i = func2();
if (func2())
{
j = func3();
if (func3())
{
…
}
}
}
Part called "Naming" is written by ringwormGO itself
- Name a function by capital letter.
Right: void Test();
Wrong: void test();
- Name a struct, class, union etc. with capital letter and variable which lowercase letter
Right:
struct Test
{
int number;
}
Test test;
Wrong:
struct test
{
int Number;
}
test Test;
- Avoid line-wasting comments, which could fit into a single line.
Right:
// This is a one-line comment
/* This is a C-style comment */
//
// This is a comment over multiple lines.
// We don’t define any strict rules for it.
//
Wrong:
//
// This comment wastes two lines
//
- Use
#pragma once
instead of guard defines in headers