diff --git a/CMakeLists.txt b/CMakeLists.txt index 217132afcd..ae24c13793 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,6 +86,13 @@ endif() message(STATUS "Project version: ${PROJECT_VERSION}") message(STATUS "Protocol version: ${DRAWPILE_PROTO_SERVER_VERSION}.${DRAWPILE_PROTO_MAJOR_VERSION}.${DRAWPILE_PROTO_MINOR_VERSION}") +if(TOOLS) + set(RUST_LIBS ON) + include(Cargo) +else() + set(RUST_LIBS OFF) +endif() + # https://doc.qt.io/qt-6/cmake-qt5-and-qt6-compatibility.html find_package(QT ${DP_MIN_QT_VERSION} NAMES Qt6 Qt5 REQUIRED) message(STATUS "Using Qt version ${QT_VERSION_MAJOR}") @@ -195,7 +202,8 @@ if(SERVER) endif() if(TOOLS) - message(STATUS "Someone deleted the tools") + message(STATUS "Adding tools") + add_subdirectory(src/tools) endif() # This must run once all target creation is finished since it walks the list of diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..e9c6407904 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,296 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", + "which", +] + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "dprectool" +version = "2.2.0-pre" +dependencies = [ + "drawdance", + "xflags", +] + +[[package]] +name = "drawdance" +version = "2.2.0-pre" +dependencies = [ + "bindgen", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f478948fd84d9f8e86967bf432640e46adfb5a4bd4f14ef7e864ab38220534ae" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "prettyplease" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "which" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +dependencies = [ + "either", + "libc", + "once_cell", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xflags" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4554b580522d0ca238369c16b8f6ce34524d61dafe7244993754bbd05f2c2ea" +dependencies = [ + "xflags-macros", +] + +[[package]] +name = "xflags-macros" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58e7b3ca8977093aae6b87b6a7730216fc4c53a6530bab5c43a783cd810c1a8" diff --git a/Cargo.toml b/Cargo.toml index e179b58fd7..3ec297a196 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,9 @@ [workspace] -members = [] +resolver = "2" +members = [ + "src/drawdance/rust", + "src/tools/dprectool", +] [workspace.package] version = "2.2.0-pre" diff --git a/cmake/Cargo.cmake b/cmake/Cargo.cmake index c67e00b25d..099af230d3 100644 --- a/cmake/Cargo.cmake +++ b/cmake/Cargo.cmake @@ -1,28 +1,99 @@ -#[[ -Adds an imported Rust executable target that is built by Cargo. -#]] -function(add_cargo_executable target) - _add_cargo(${target} TRUE ${ARGN}) +# SPDX-License-Identifier: MIT +find_program(CARGO_COMMAND cargo REQUIRED + PATHS $ENV{HOME}/.cargo/bin + DOC "Cargo executable" +) + +# SPDX-SnippetBegin +# SPDX-License-Identifier: MIT +# SDPX—SnippetName: static libs detection from corrosion +function(_corrosion_determine_libs_new target_triple out_libs) + set(package_dir "${CMAKE_BINARY_DIR}/corrosion/required_libs") + # Cleanup on reconfigure to get a cleans state (in case we change something in the future) + file(REMOVE_RECURSE "${package_dir}") + file(MAKE_DIRECTORY "${package_dir}") + set(manifest "[package]\nname = \"required_libs\"\nedition = \"2018\"\nversion = \"0.1.0\"\n") + string(APPEND manifest "\n[lib]\ncrate-type=[\"staticlib\"]\npath = \"lib.rs\"\n") + string(APPEND manifest "\n[workspace]\n") + file(WRITE "${package_dir}/Cargo.toml" "${manifest}") + file(WRITE "${package_dir}/lib.rs" "pub fn add(left: usize, right: usize) -> usize {left + right}\n") + + if(target_triple) + execute_process( + COMMAND + ${CARGO_COMMAND} rustc --verbose --color never --target=${target_triple} -- --print=native-static-libs + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/corrosion/required_libs" + RESULT_VARIABLE cargo_build_result + ERROR_VARIABLE cargo_build_error_message + ) + else() + execute_process( + COMMAND + ${CARGO_COMMAND} rustc --verbose --color never -- --print=native-static-libs + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/corrosion/required_libs" + RESULT_VARIABLE cargo_build_result + ERROR_VARIABLE cargo_build_error_message + ) + endif() + + if(cargo_build_result) + message(SEND_ERROR "Determining required native libraries - failed: ${cargo_build_result}.") + message(SEND_ERROR "The cargo build error was: ${cargo_build_error_message}") + return() + else() + # The pattern starts with `native-static-libs:` and goes to the end of the line. + if(cargo_build_error_message MATCHES "native-static-libs: ([^\r\n]+)\r?\n") + string(REPLACE " " ";" "libs_list" "${CMAKE_MATCH_1}") + set(stripped_lib_list "") + foreach(lib ${libs_list}) + # Strip leading `-l` (unix) and potential .lib suffix (windows) + string(REGEX REPLACE "^-l" "" "stripped_lib" "${lib}") + string(REGEX REPLACE "\.lib$" "" "stripped_lib" "${stripped_lib}") + list(APPEND stripped_lib_list "${stripped_lib}") + endforeach() + set(libs_list "${stripped_lib_list}") + # Special case `msvcrt` to link with the debug version in Debug mode. + list(TRANSFORM libs_list REPLACE "^msvcrt$" "\$<\$:msvcrtd>") + else() + message(SEND_ERROR "Determining required native libraries - failed: Regex match failure.") + message(SEND_ERROR "`native-static-libs` not found in: `${cargo_build_error_message}`") + return() + endif() + endif() + set("${out_libs}" "${libs_list}" PARENT_SCOPE) +endfunction() +# SPDX-SnippetEnd + +function(_cargo_set_libs target triple) + if(NOT "${triple}") + set(cache_var "CARGO_LIBS_${triple}") + else() + set(cache_var "CARGO_LIBS_HOST") + endif() + + set(libs "${${cache_var}}") + if(libs) + message(STATUS "Re-used Rust libraries: ${libs}") + else() + _corrosion_determine_libs_new("${triple}" libs) + set("${cache_var}" "${libs}" CACHE INTERNAL "") + message(STATUS "Determined Rust libraries: ${libs}") + endif() + + set_target_properties("${target}" PROPERTIES + INTERFACE_LINK_LIBRARIES "${libs}" + ) endfunction() #[[ Adds an imported Rust static library target that is built by Cargo. #]] -function(add_cargo_library target) - _add_cargo(${target} FALSE ${ARGN}) -endfunction() - -function(_add_cargo target is_exe) +function(add_cargo_library target package) set(options ALL_FEATURES NO_DEFAULT_FEATURES) - set(singleValueArgs PACKAGE MANIFEST_PATH) + set(singleValueArgs MANIFEST_PATH) set(multiValueArgs FEATURES) cmake_parse_arguments(PARSE_ARGV 2 ARG "${options}" "${singleValueArgs}" "${multiValueArgs}") - find_program(CARGO_COMMAND cargo REQUIRED - PATHS $ENV{HOME}/.cargo/bin - DOC "Cargo executable" - ) - if(CMAKE_CROSSCOMPILING) if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|[Aa][Aa][Rr][Cc][Hh]64") set(arch aarch64) @@ -62,28 +133,14 @@ function(_add_cargo target is_exe) set(cargo_dir ${CMAKE_CURRENT_BINARY_DIR}/cargo) set(cargo_target_dir "${cargo_dir}/$<$:${triple}/>$>") - if(is_exe) - set(all ALL) - set(out_name ${target}${CMAKE_EXECUTABLE_SUFFIX}) - set(out_kind RUNTIME) - else() - set(all "") - set(out_name ${CMAKE_STATIC_LIBRARY_PREFIX}${ARG_PACKAGE}${CMAKE_STATIC_LIBRARY_SUFFIX}) - set(out_kind ARCHIVE) - endif() - - if(CMAKE_${out_kind}_OUTPUT_DIRECTORY) - set(out_dir ${CMAKE_${out_kind}_OUTPUT_DIRECTORY}) + set(out_name ${CMAKE_STATIC_LIBRARY_PREFIX}${package}${CMAKE_STATIC_LIBRARY_SUFFIX}) + if(CMAKE_ARCHIVE_OUTPUT_DIRECTORY) + set(out_dir ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) else() set(out_dir ${CMAKE_CURRENT_BINARY_DIR}) endif() - if(ARG_PACKAGE) - set(extra_comment " with packages ${ARG_PACKAGE}") - endif() - add_custom_target(cargo-build_${target} - ${all} BYPRODUCTS "${out_dir}/${out_name}" COMMAND ${CMAKE_COMMAND} -E env MACOSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET} ${CARGO_COMMAND} build @@ -92,13 +149,13 @@ function(_add_cargo target is_exe) "$<$:--all-features>" "$<$:--no-default-features>" "$<$:--target;${triple}>" - "$<$:--package;${ARG_PACKAGE}>" + "$<$:--package;${package}>" "$<$:--verbose>" --profile "$,dev,$>>" --target-dir ${cargo_dir} COMMAND ${CMAKE_COMMAND} -E copy_if_different "${cargo_target_dir}/${out_name}" "${out_dir}/${out_name}" COMMAND_EXPAND_LISTS - COMMENT "Running cargo${extra_comment}" + COMMENT "Running cargo with package ${package}" VERBATIM ) @@ -106,43 +163,17 @@ function(_add_cargo target is_exe) # rules about finding package directories and it does not work if someone # does not specify packages at all but it works for how this function is # used today, so YAGNI - if(ARG_PACKAGE AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) - foreach(item IN LISTS ARG_PACKAGE) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.20) + foreach(item IN LISTS package) file(GLOB_RECURSE sources ${PROJECT_SOURCE_DIR}/src/${item}/*) target_sources(cargo-build_${target} PRIVATE ${sources}) source_group(TREE "${PROJECT_SOURCE_DIR}/src/${item}" PREFIX "Source Files" FILES ${sources}) endforeach() endif() - if(is_exe) - add_executable(${target} IMPORTED GLOBAL) - else() - add_library(${target} STATIC IMPORTED GLOBAL) + add_library(${target} STATIC IMPORTED GLOBAL) - # Adapted from corrosion. Required for successful linking of anything - # that uses the Rust Standard Library - set(libs "") - if(WIN32) - list(APPEND libs "advapi32" "userenv" "ws2_32" "bcrypt") - if(MSVC) - list(APPEND libs "$<$:msvcrtd>") - # CONFIG takes a comma seperated list starting with CMake 3.19, but we still need to - # support older CMake versions. - set(config_is_release "$,$,$>") - list(APPEND libs "$<${config_is_release}:msvcrt>") - else() - list(APPEND libs "gcc_eh" "pthread") - endif() - elseif(APPLE) - list(APPEND libs "System" "resolv" "c" "m") - else() - list(APPEND libs "dl" "rt" "pthread" "gcc_s" "c" "m" "util") - endif() - - set_target_properties(${target} PROPERTIES - INTERFACE_LINK_LIBRARIES "${libs}" - ) - endif() + _cargo_set_libs("${target}" "${triple}") add_dependencies(${target} cargo-build_${target}) set_target_properties(${target} PROPERTIES diff --git a/src/drawdance/libmsg/dpmsg/protocol.h b/src/drawdance/libmsg/dpmsg/protocol.h new file mode 100644 index 0000000000..31f3987881 --- /dev/null +++ b/src/drawdance/libmsg/dpmsg/protocol.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +#ifndef DPENGINE_PROTOCOL_H +#define DPENGINE_PROTOCOL_H +#include + + +const char *DP_protocol_version(void); + + +#endif diff --git a/src/drawdance/rust/Cargo.toml b/src/drawdance/rust/Cargo.toml new file mode 100644 index 0000000000..63063c7467 --- /dev/null +++ b/src/drawdance/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "drawdance" +version = "2.2.0-pre" +edition = "2021" + +[lib] +path = "lib.rs" + +[build-dependencies] +bindgen = "0.66.1" diff --git a/src/drawdance/rust/build.rs b/src/drawdance/rust/build.rs new file mode 100644 index 0000000000..e1ab1c5f4d --- /dev/null +++ b/src/drawdance/rust/build.rs @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +use std::env; +use std::path::PathBuf; + +fn main() { + println!("cargo:rerun-if-changed=wrapper.h"); + + let bindings = bindgen::Builder::default() + .header("wrapper.h") + .clang_arg("-I../libcommon") + .clang_arg("-I../libmsg") + .clang_arg("-I../libengine") + .allowlist_function("DP_.*") + .allowlist_type("DP_.*") + .allowlist_var("DP_.*") + .blocklist_file(".*dpcommon[/\\](common|conversions)\\.h") + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .generate() + .expect("Couldn't generate bindings for drawdance"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings for drawdance"); +} diff --git a/src/drawdance/rust/lib.rs b/src/drawdance/rust/lib.rs new file mode 100644 index 0000000000..5dfd771fa0 --- /dev/null +++ b/src/drawdance/rust/lib.rs @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/src/drawdance/rust/wrapper.h b/src/drawdance/rust/wrapper.h new file mode 100644 index 0000000000..f2e4b45c52 --- /dev/null +++ b/src/drawdance/rust/wrapper.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt new file mode 100644 index 0000000000..7af31496ab --- /dev/null +++ b/src/tools/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MIT + +set_property(SOURCE dprectool/main.c PROPERTY SKIP_AUTOGEN ON) + +add_cargo_library(dprectool_rust dprectool) +add_executable(dprectool dprectool/main.c) +target_link_libraries(dprectool PUBLIC dprectool_rust dpengine) diff --git a/src/tools/dprectool/Cargo.toml b/src/tools/dprectool/Cargo.toml new file mode 100644 index 0000000000..0c6b646e9b --- /dev/null +++ b/src/tools/dprectool/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "dprectool" +version = "2.2.0-pre" +edition = "2021" + +[lib] +crate-type = ["staticlib"] +path = "lib.rs" + +[dependencies] +drawdance = { path = "../../drawdance/rust" } +xflags = "0.3.1" diff --git a/src/tools/dprectool/lib.rs b/src/tools/dprectool/lib.rs new file mode 100644 index 0000000000..db85238266 --- /dev/null +++ b/src/tools/dprectool/lib.rs @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)] +pub enum Format { + #[default] + Guess, + Binary, + Text, + Version, +} + +impl std::str::FromStr for Format { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "guess" => Ok(Self::Guess), + "binary" => Ok(Self::Binary), + "text" => Ok(Self::Text), + "version" => Ok(Self::Version), + _ => Err(format!( + "invalid format '{s}', should be one of 'guess', 'binary', \ + 'text' or 'version'" + )), + } + } +} + +#[no_mangle] +pub extern "C" fn dprectool_main() -> std::os::raw::c_int { + let flags = xflags::parse_or_exit! { + /// Displays version information and exits. + optional -v,--version + /// Output file. Use '-' for stdout, which is the default. + optional -o,--out output: String + /// Output format, one of 'guess' (the default), 'binary' (.dprec), + /// 'text' (.dptxt). Alternatively, 'version' will output the recording + /// version and exit. + optional -f,--format format: Format + /// Performs ACL filtering. This will filter out any commands that the + /// user wasn't allowed to actually perform, such as drawing on a layer + /// that they didn't have permission to draw on. The Drawpile client + /// would also filter these out when playing back a recording. + optional -A,--acl + /// Print message frequency table. + optional --msg-freq + /// Input recording file. + optional input: String + }; + + if flags.version { + let protover = std::str::from_utf8(drawdance::DP_PROTOCOL_VERSION).unwrap(); + println!("Protocol version: {}", protover); + return 0; + } + + unsafe { drawdance::DP_player_free(std::ptr::null_mut()) } + 0 +} diff --git a/src/tools/dprectool/main.c b/src/tools/dprectool/main.c new file mode 100644 index 0000000000..b56f51acdb --- /dev/null +++ b/src/tools/dprectool/main.c @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +int dprectool_main(void); + +int main(void) +{ + return dprectool_main(); +}